In drf3 you can now implement a writable nested serializer by overriding the create() method and handling validated_data yourself. However, what if you've a multi-level nested relationship in the models like so:
class Order(models.Model):
"""
Order model to aggregate all the shipments created by a user at a particular time.
"""
created_at = models.DateTimeField(
verbose_name='created at',
auto_now_add=True
)
updated_at = models.DateTimeField(
verbose_name='updated at',
auto_now=True
)
class Shipment(models.Model):
"""
Many to One Relationship with the Orders Model. Aggregates all the details of a shipment being sent.
"""
created_at = models.DateTimeField(
verbose_name='created at',
auto_now_add=True
)
updated_at = models.DateTimeField(
verbose_name='updated at',
auto_now=True
)
order = models.ForeignKey(
to=Order
)
class ItemDetail(models.Model):
"""
Specifies details of the shipment contents. One to One relationship with the Shipment Model.
"""
shipment = models.OneToOneField(
to=Shipment,
primary_key=True
)
CONTENT_TYPES = (
('D', 'Documents'),
('P', 'Products')
)
content = models.CharField(
verbose_name='package contents',
max_length=1,
choices=CONTENT_TYPES,
default='P'
)
How would I write a serializer for order with custom create method to handle such a case? All the examples I've seen including the one on the official page has just one level of nested relationship.
Read is working fine with the depth argument. However, I'd really appreciate any help with writing the create/update method.
The writable nested serializer is explained in the documentation.
Please do not recreate a new serializer in the create/update. Once you hit the top most serializer create/update, all your data are validated, including the nested ones.
At this point, you'll have to write by yourself the mapping from the validated_data to your various objects.
I tried to make it automatic for DRF 2.x but it turns out that there was too many use case, some of which were exclusives. Therefore DRF leaves that work upon the developer - i.e. you.
One way is to have two serializers, firs ItemDetailSerializer
which will call ShipmentSirializer
to handle Order
and Shipment
creation and then create ItemDetail
itself.
Something like:
class ItemDetailSerializer(serializers.ModelSerializer):
"""
# Describe here all relationships
"""
class Meta:
model = ItemDetail
def create(self, validated_data):
shipment = validated_data.pop('shipment')
shipment_serializer = ShipmentSerializer(data=shipment)
if shipment_serializer.is_valid()
shipment_serializer.save()
item_detail = ItemDetail.objects.create(shipment=shipment_serializer.instance,
**validated_data)
return item_detail
And for the ShipmentSerializer
you can follow documentation about nested relations, that you've mentioned.
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