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.
Related
class UserViewSerializer(DynamicFieldsMixin,serializers.ModelSerializer):
followers_set = UserViewSerializer(required=False,many=True)
class Meta:
model = User
fields = ('id','email','username','password','followers_set')
depth = 2
is there anyway i can use this function without getting this error?
followers_set = UserViewSerializer(source='follows',required=False,many=True)
NameError: name 'UserViewSerializer' is not defined
i tried SerializerMethodField but then i can't use depth option there
following_set = serializers.SerializerMethodField()
def get_following_set(self, user):
return UserViewSerializer(User.objects.filter(follows__author=user), many=True).data
using SerializerMethodField gives me error of:
RecursionError at /api/users/
maximum recursion depth exceeded
Can somebody help me please?
The simplest way to handle this is to make three serializers: one without a followers_set, one with a followers_set that uses the previous one, and one that users the second model, so:
# no followers_set
class UserViewSerializer0(DynamicFieldsMixin,serializers.ModelSerializer):
class Meta:
model = User
fields = ('id','email','username')
# followers_set, but only depth 1
class UserViewSerializer1(DynamicFieldsMixin,serializers.ModelSerializer):
followers_set = UserViewSerializer0(source='follows',required=False,many=True)
class Meta:
model = User
fields = ('id','email','username')
# followers_set, with depth 2
class UserViewSerializer(DynamicFieldsMixin,serializers.ModelSerializer):
followers_set = UserViewSerializer1(source='follows',required=False,many=True)
class Meta:
model = User
fields = ('id','email','username')
This is more safe as well, since you can not define recursive loops, unless you indeed work with SerializerMethodField, which is not a good idea if you add extra serializers.
It might however be better no to go to depth two, but stick to depth one. It will generate large responses already, make creating objects more cumbersome, and it will result in a lot of extra queries.
Assume there is a child and parent relation in models, such as:
class Foo(models.Model):
parent = models.ForeignKey('Foo', related_name='children')
Now I want to have a serializer to show children of a Foo object, something like this:
class FooSerializer(serializers.ModelSerializer):
children = FooSerializer(many=True)
class Meta:
model = Foo
fields = '__all__'
But this gives me error that it does not recognize FooSerializer when creating that class which is correct regarding the way python parses the class. How could I implement such relation and have a serializer to get its children.
I must mention that I want to able to use depth option of nested serializer.
I am using django 2.2.7 and rest framework 3.10.1.
Edit
There may be some numbers of nested levels which it must be stopped using depth option, after some levels it must be flatten, so I wanted to able to use depth option along nested serializer.
depth attribute is for ForeignKey relationships, In your case, it's reverse-FK relation, So it won't work
You can achieve the depth like feature by using multiple serializer in Nested configuration.
Example 1: result similar to depth=1
class FooBaseSerializerLevel1(serializers.ModelSerializer):
class Meta:
model = Foo
fields = '__all__'
class FooBaseSerializerLevel0(serializers.ModelSerializer):
children = FooBaseSerializerLevel1(many=True)
class Meta:
model = Foo
fields = '__all__'
Example 2: result similar to depth=2
class FooBaseSerializerLevel2(serializers.ModelSerializer):
class Meta:
model = Foo
fields = '__all__'
class FooBaseSerializerLevel1(serializers.ModelSerializer):
children = FooBaseSerializerLevel2(many=True)
class Meta:
model = Foo
fields = '__all__'
class FooBaseSerializerLevel0(serializers.ModelSerializer):
children = FooBaseSerializerLevel1(many=True)
class Meta:
model = Foo
fields = '__all__'
The key point is that, do not define the children where you want to stop the nested effect
Based on another answer, I wrote a version which supports depth option:
class FooSerializer(serializers.ModelSerializer):
children = serializers.SerializerMethodField()
def get_children(self, obj):
if obj.children:
depth = getattr(self.Meta, 'depth', None)
if not depth:
depth = self.context.get('depth', 0)
if depth:
return SessionSerializer(obj.children.all(),
many=True,
context={'depth': depth - 1}).data
else:
return [child.id for child in obj.children.all()]
else:
return []
It supports depth option too.
So, I have a foreign key to my User model in many of my models. Now, the serializers for these models are nested, in that they include the entire user object rather than just the id. I have done so as shown bellow:
class BadgeSerializer(serializers.ModelSerializer):
user = UserSerializer(read_only=True)
class Meta:
model = Badge
fields = '__all__'
It works as expected. However, I seldom find myself in a situation where I want just the id. I was wondering what is the best way to conditionally nest my BadgeSerializer...
Now, the best solution I can think of is to have a non-nested BadgeSerializer, which includes only the user id. And then have a NestedBadgeSerializer (extending BadgeSerializer) which does nest the User model and include the entire user object.
class BadgeSerializer(serializers.ModelSerializer):
class Meta:
model = Badge
fields = '__all__'
class NestedBadgeSerializer(BadgeSerializer):
user = UserSerializer(read_only=True)
class Meta:
model = Badge
fields = '__all__'
I am NOT sure if that's the proper way though.
Suppose you want to include 5 images and the total image count for your restaurant when you serialize a restaurant.
You can query DB for each field in separate method,
but it would be beneficial to work in one method to utilize a QuerySet.
Is there a way to serialize multiple fields at once in DRF?
If all of these fall under one model then building a simple model serializer will account for them all. Take for instance:
# Model
class Restaurant(models.Model):
#property
def image_count(self):
queryset = apps.get_model('app_label', 'Image')
count = queryset.objects.filter(restaurant=self).count()
return count
class Image(models.Model):
restaurant = models.ForeignKey(Restaurant, related_name="image_set")
image = models.ImageField()
Serializers.py
class RestaurantSerializer(serializers.ModelSerializer):
class Meta:
model = Restaurant
fields = ['image_count', ]
# Property allows something as such to be serialized, the method could also just use the related name.
If you want to further serialize the Image object you must read http://www.django-rest-framework.org/api-guide/relations/
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.