I have a situation where my client is attempting to write a representation that includes a list of fk's
{
languages: [1]
last_name: "Beecher"
settings: 1
state: "NY"
}
But when reading it in, I'd like to have a nested representation to cut back on roundtrips
{
languages: [{id:1, created:2013-07-21T01:38:33.569Z, modified:2013-07-21T01:38:33.569Z, language:testing}]
last_name: "Beecher"
settings: {
created: "2013-07-20T22:04:17.998Z"
email_blog: false
email_booking_accepted_denied: false
email_booking_request: false
email_friend_joined: false
email_groups_added_network: false
email_new_review: false
email_news: false
email_upcoming_booking_remind: false
id: 1
mobile_booking_accepted_denied: false
mobile_booking_request: false
mobile_friend_joined: false
mobile_groups_added_network: false
mobile_new_review: false
mobile_upcoming_booking_remind: false
modified: "2013-07-20T22:04:18.000Z"
user: 1
}
state: "NY"
}
Reading is no problem using a model serializer and depth=1 - but attempting to write gives an error "ValueError('instance should be a queryset or other iterable with many=True')" When attempting to check a many related field for iter
Conversely, turning off depth makes writing work just as I'd like, but reading is no good.
Is there something I'm totally missing here? It seems like it should be a simple change, but I can only get one or the other working
Serializers in Django REST Framework are responsible for converting objects into data types understandable by javascript and front-end frameworks. Serializers also provide deserialization, allowing parsed data to be converted back into complex types, after first validating the incoming data.
In function based views we can pass extra context to serializer with "context" parameter with a dictionary. To access the extra context data inside the serializer we can simply access it with "self. context". From example, to get "exclude_email_list" we just used code 'exclude_email_list = self.
In general, I use nested serializers when I want an interface where model B is always read (or created) together with model A. An example of this would be a Pizza model with a many-to-many relationship to Topping .
The HyperlinkedModelSerializer class is similar to the ModelSerializer class except that it uses hyperlinks to represent relationships, rather than primary keys. By default the serializer will include a url field instead of a primary key field.
Thanks to previous posts, I went with a similar solution based off get_serializer_class
for this.
I also wanted to be able to change the serializer class depending on method.
First, I added an attribute to the view class with a dictionary mapping request methods to serializer classes.
serializer_classes = {
'GET': NestedSerializer,
'POST': FlatSerializer
}
Then, I defined a mixin to use where I want this behavior.
class SwappableSerializerMixin(object):
def get_serializer_class(self):
try:
return self.serializer_classes[self.request.method]
except AttributeError:
logger.debug('%(cls)s does not have the required serializer_classes'
'property' % {'cls': self.__class__.__name__})
raise AttributeError
except KeyError:
logger.debug('request method %(method)s is not listed'
' in %(cls)s serializer_classes' %
{'cls': self.__class__.__name__,
'method': self.request.method})
# required if you don't include all the methods (option, etc) in your serializer_class
return super(SwappableSerializerMixin, self).get_serializer_class() es
I had the same problem and it looks like quite a few others have it too. Carlton Gibson answer actually lead me to my hacky solution. I ended up using a ModelSerializer with the depth set and created the following mixin to use in the views.
class ReadNestedWriteFlatMixin(object):
"""
Mixin that sets the depth of the serializer to 0 (flat) for writing operations.
For all other operations it keeps the depth specified in the serializer_class
"""
def get_serializer_class(self, *args, **kwargs):
serializer_class = super(ReadNestedWriteFlatMixin, self).get_serializer_class(*args, **kwargs)
if self.request.method in ['PATCH', 'POST', 'PUT']:
serializer_class.Meta.depth = 0
return serializer_class
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With