I have a model which consists of two ForeignKeys. I am only interested in parsing the content of the ForeignKeys, so i'm using the depth variable, which basically gives me all columns of the tables referenced with the FK. Is there a way to select which columns there should be included?
class SomeSerializer(serializers.ModelSerializer):
class Meta:
model = MyAwesomeModel
fields = ('id', 'fk_one','fk_two')
depth = 1
Try using nested serializers. Documentation here.
Example:
class FKOneSerializer(serializers.ModelSerializer):
class Meta:
model = FKOne
fields = ('name', 'id')
class SomeSerializer(serializers.ModelSerializer):
fk_one = FKOneSerializer()
class Meta:
model = MyAwesomeModel
fields = ('id', 'fk_one','fk_two')
EDIT:
Similar answer here by the creator of the Django Rest Framework. Also includes some related notes, including that nested serializers are read-only and that you may need to include a source argument on the serializer field.
Related
model 1
class Users(models.Model):
employee_name = models.CharField(max_length=50)
dob=models.DateField(max_length=8)
email=models.EmailField(max_length=254,default=None)
pancard=models.CharField(max_length=25,default=None)
aadhar=models.CharField(max_length=20,default=None)
personal_email_id=models.EmailField(max_length=254,default=None)
phone = PhoneField(blank=True)
emergency_contact_no=models.IntegerField(default=None)
emergency_contact_name=models.CharField(max_length=100,null=True)
relation=models.CharField(max_length=25,default=None)
blood_group=models.CharField(max_length=25,choices=BLOOD_GROUP_CHOICES,null=True)
desingnation=models.ForeignKey(Designation,on_delete=CASCADE,related_name="desingnation")
billable_and_non_billable=models.CharField(max_length=25,choices=BILLABLE_and_NON_BILLABLE_CHOICES,default='Billable')
joining_date=models.DateField(max_length=15,null=True)
relieving_date=models.DateField(max_length=15,null=True)
def __str__(self):
return self.employee_name
model 2
class Consolidated(models.Model):
emp_name=models.ForeignKey(Users,on_delete=CASCADE)
proj_name=models.ForeignKey(Project,on_delete=CASCADE)
custom_name=models.ForeignKey(Client,on_delete=CASCADE)
Cons_date=models.ForeignKey(Add_Timelog,on_delete=CASCADE)
bill_no_bill=models.ForeignKey(Users,on_delete=CASCADE,related_name="billable_and_non_billable+")
def __str__(self):
return str(self.emp_name)
Serializers
class UserSerializers(serializers.ModelSerializer):
class Meta:
model= Users
fields = '__all__'
class Consolidated_serializers(serializers.ModelSerializer):
class Meta:
model=Consolidated
fields= '__all__'
Viewsets
class UserViewset(viewsets.ModelViewSet):
permission_classes=(permissions.IsAdminUser,)
queryset=models.Users.objects.all()
serializer_class=serializers.UserSerializers
class Consolidated_ViewSet(viewsets.ModelViewSet):
permission_classes=(permissions.IsAdminUser,)
queryset=models.Consolidated.objects.all()
serializer_class=serializers.Consolidated_serializers
Actually I was stucked in the middle, as I need to take the values from 'billable_and_non_billable' field from the Users model and display those values under Consolidated model bill_no_bill field. With the above code I can only take the employee_name values from the Users model to the emp_name of Consolidated model and the same value is getting displayed in the bill_no_bill field. Please help me find any ways for this problem as I am new to this Django. Basically its needs to be a API which operates GET method.
You are getting same value because you are using Foreign Key to the user model for both emp_name and bill_no_bill. Foreign keys are used for many to one relations between models.
See: https://docs.djangoproject.com/en/4.0/topics/db/examples/many_to_one/
So your Consolidated Model should be:
class Consolidated(models.Model):
employee=models.ForeignKey(Users,on_delete=CASCADE)
project=models.ForeignKey(Project,on_delete=CASCADE)
custom_name=models.ForeignKey(Client,on_delete=CASCADE)
cons_date=models.ForeignKey(Add_Timelog,on_delete=CASCADE)
To get the values of these fields you can use Nested Objects Representation in DRF serializers.
So the consolidated serializer becomes:
class ConsolidatedSerializer(serializers.ModelSerializer):
employee = UserSerializer()
class Meta:
model = Consolidated
fields = ['employee', 'project', 'custom', 'date']
The bill_no_bill field would be part of the returned object in viewset.
Alternatively you can override the to_representation method of serializer or SerializerMethodField
I need to show all content of every related field on the way. If I try to set depth = sys.maxint it receives an error:
AssertionError: 'depth' may not be greater than 10.
Serializer exapmle:
class AppleSerializer(serializers.ModelSerializer):
class Meta:
model = Apple
fields = '__all__'
depth = sys.maxint
So no values greater then 10. I have relation threads of more than 10 models so need some bigger depth. What is the way to set it bigger or just tell serializer to substitute content in all related fields trough all thread?
EDITED
The best practice I riched is to just make special serializers with expanding related fields in each of them so that'd look like this:
class OneSerializer(serializers.ModelSerializer):
class Meta:
model = One
fields = '__all__'
class TwoSerializer(serializers.ModelSerializer):
one = OneSerializer()
class Meta:
model = Two
fields = '__all__'
class ThreeSerializer(serializers.ModelSerializer):
two = TwoSerializer()
class Meta:
model = Three
fields = '__all__'
But it requires to do all this middleware serializers so if I need only one the last in this serializers chain which has like 20 related models one by one I'd be required to create 20 not necessary serializers.
Question is about using standard Django backward related manager name in DRF.
I have following serializer
class ExtraUserSerializer(serializers.ModelSerializer):
boatmodel_set = serializers.PrimaryKeyRelatedField(many=True,
queryset=BoatModel.objects.all())
class Meta:
model = get_user_model()
fields = ("id", "username", 'boatmodel_set', )
This serializer represents primary model ExtraUser and boat_model set represents backward relationship to secondary model BoatModel. Related name “boatmodel_set” chosen simply because main core Django site uses this standard “secondarymodel_set” conventional backward related manager name so that in DRF part I had to use related_name = “ boatmodel_set” as well in order to not change code in the main part.
Question is - is it possible to keep related_name = “ boatmodel_set” but represent it in rendered json as , for example “boats”??
Thank you
Yes, you can just specify the source= parameter [drf-doc], and name the field differently, like:
class ExtraUserSerializer(serializers.ModelSerializer):
boats = serializers.PrimaryKeyRelatedField(
many=True,
queryset=BoatModel.objects.all(),
source='boatmodel_set'
)
class Meta:
model = get_user_model()
fields = ('id', 'username', 'boats')
Here the JSON-side will contain "boats": ..., whereas the model side will still use myuser.boatmodel_set.all().
Right now I am creating a user department with a list of users that are a foreign key back to the main user model. I had this working yesterday, but for some reason I screwed it up. I imagine it has something to do with the serializers. I want to be able to post a list of users in this format
['jack', 'tom']
However, even using the raw data api this is not allowing me to do this. Here is my code:
Serializers:
class DepartmentSerializer(serializers.ModelSerializer):
user_department = UserSerializer(many=True)
class Meta:
model = Departments
fields = '__all__'
class DepartmentUpdateSerializer(serializers.ModelSerializer):
user_department = UserSerializer(many=True)
class Meta:
model = Departments
fields = ['department_name', 'department_head', 'user_department']
I swear yesterday it was allowing me to select from a list of users in the api. I could also post and it would work from the front end. However, now whenever I create a department it's expecting a dictionary, which I am not trying to pass.
Dudes, for whatever reason, removing () after the UserSerializer fixed it. If anyone can explain why that would be even better!
class DepartmentSerializer(serializers.ModelSerializer):
user_department = UserSerializer
class Meta:
model = Departments
fields =['department_name', 'department_head', 'user_department']
class DepartmentUpdateSerializer(serializers.ModelSerializer):
user_department = UserSerializer
class Meta:
model = Departments
fields = ['department_name', 'department_head', 'user_department']
When you use the nested serializer you need to add the nested serializer field (user_department in your case) to the fields too, as you can see you used
fields = '__all__'
which does not include your nested serializer field, you need to manually add that to the meta fields
I am working through a tutorial that includes the building of an articles app. I have an Article model that I am serializing and I am curious about why I need to explicitly set certain fields when using a ModelSerializer.
Here is my model:
from django.db import models
from core.models import TimestampedModel
class Article(TimestampedModel):
slug = models.SlugField(db_index=True, max_length=255, unique=True)
title = models.CharField(db_index=True, max_length=255)
description = models.TextField()
body = models.TextField()
author = models.ForeignKey('profiles.Profile', on_delete=models.CASCADE, related_name='articles')
def __str__(self):
return self.title
Pretty standard stuff. Next step is to serialize the model data in my serializers.py file:
class ArticleSerializer(serializers.ModelSerializer):
author = ProfileSerializer(read_only=True) # Three fields from the Profile app
description = serializers.CharField(required=False)
slug = serializers.SlugField(required=False)
class Meta:
model = Article
fields = (
'author',
'body',
'createdAt',
'description',
'slug',
'title',
'updatedAt',
)
Specifically, why do I need to explicitly state the author, description, and slug fields if I am using serializers.ModelSerializer and pulling those fields in from my model in my class Meta: below?
Thanks!
In the Django-Rest-Framework documentation, drf-docs/model_serializer/specifying-which-fields-to-include it says:
If you only want a subset of the default fields to be used in a model serializer, you can do so using fields or exclude options, just as you would with a ModelForm. It is strongly recommended that you explicitly set all fields that should be serialized using the fields attribute. This will make it less likely to result in unintentionally exposing data when your models change.
Therefore by using fields = in the Serializer META, you can specify just the needed fields, and not returning vital fields like id, or exessive information like updated and created timestamps.
You can also instead of using fields, use exclude, which again takes in a tuple, but just excludes the fields you don't want.
These are especially useful when your database table contains a lot of information, returning all this information, especially if it is listed, can result in large return JSON's, where the frontend may only use a small percentage of the sent data.
DRF has designed their framework like this to specifically combat these problems.
In my opinion, we should define field in serializer for:
Your api use serializer don't need all data of your models. Then you can limit field can get by serializer. It faster if you have so much data.
You dont want public all field of your model. Example like id
Custom field in serializer like serializers.SerializerMethodField() must define in fields for work
Finally, iF you dont want, you can define serializer without define fields. Its will work normally