Implement a writable serializer for multilevel nes

2019-07-18 00:02发布

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.

2条回答
叼着烟拽天下
2楼-- · 2019-07-18 00:28

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.

查看更多
贪生不怕死
3楼-- · 2019-07-18 00:41

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.

查看更多
登录 后发表回答