1

My serializer has been mysteriously dropping some related fields but not others. I have tried to find documentation on the validation methods order but cannot find anything on DRF's site. I then added some print statements to a bunch of methods to see where the values get dropped:

  • the field values are present in the view in the request
  • the field values are present in the validate_empty_values call
  • the validate_<field_name> method is not called for the fields in question, but I suspect these methods do not get called for related fields
  • the field values are not present in the validate method

This is odd seeing as how other related fields are defined in the exact same way and are working as desired.

class ExampleSerializer(ModelSerializer):
    account = AccountSerializer(read_only=True)
    address = AddressSerializer()
    marketplace = MarketplaceSerializer(read_only=True)
    product = ProductSerializer(read_only=True)
    ...

    class Meta:
        model = ExampleOrder
        fields = (
            'id',
            'marketplace', 
            'account',
            'product',
            'address',
            ....
        )


    def validate_empty_values(self, data):
        print('validating empty: ', data)  # value present at this stage
        filtered = {}
        for key, value in data.items():
            if not key:
                continue
            if value == "" or value == "null":
                value = None
            filtered[key] = value
        print('filtered: ', filtered)  # values are present here after filtering empty keys
        return super(PurchaseOrderSerializer, self).validate_empty_values(filtered)

    def validate(self, attrs):
        print('validate all: ', attrs)  # values are not present here
        ...

    def validate_<fieldname>(self, value):
        print('related field: ', value)  # doesnt get called but I suspect related fields do not call this on validate field
        ...

    def update(self, instance, validated_data):
        print('updating: ', validated_data)  # doesn't reach this method
        ...

In the above example only marketplace and address have their values serialized or fetch the appropriate model if the serializer is read_only. All the other related fields I declared above are filtered out for some reason and the data never makes it into the validate method and Validation errors are raised because those fields are required. The related serializers are defined in the standard manner without overriding anything:

class AddressSerializer(ModelSerializer):

    class Meta:
        model = Address
        fields = (
            'id',
            'address_line1',
            'address_line2',
            'city',
            'state',
            'zipcode',
        )

Here is an example of the attrs that make it through to the validate method:

OrderedDict([
    ... 
    ('address', OrderedDict([
        ('address_line1', '123 STREET LN'), 
        ('address_line2', ''), 
        ('city', 'SPRINGFIELD'), 
        ('state', 'MA'), 
        ('zipcode', '12345-2926')
    ])), 
    ('user', <User: me>), 
    ('marketplace', <MarketplaceAccount: Marketplace1:ABCDEFGH123>),
    ...
])

As you can see the address was serialized and the marketplace object was fetched so the problem doesn't seem to be read_only. What is the validation order for the latest DRF? How do I get the other read_only fields to return their respective models like the marketplace field? Any direction would be appreciated.

EDIT1: Model:

class ExampleOrder(models.Model):
    ...
    marketplace = models.ForeignKey('accounts.MarketplaceAccount', null=True, blank=True)
    user = models.ForeignKey(User, related_name='orders')
    product = models.ForeignKey('products.Product',
                                         related_name='orders',
                                         null=True,
                                         blank=True,
                                         on_delete=models.SET_NULL)
    address = models.ForeignKey('accounts.Address',
                                         related_name='orders',
                                         on_delete=models.CASCADE,
                                         null=True,
                                         blank=True)
    account = models.ForeignKey('accounts.Account',
                                       related_name='orders',
                                       null=True,
                                       blank=True,
                                       on_delete=models.SET_NULL)
    ...

    class Meta:
        unique_together = (('user', 'order_id', 'marketplace'),)

Edit1:

After digging around a bit more I found these posts:

It seems either separate views, separate serializers in a viewset or separate fields in the same serializer to handle the read/writes is the approach but these posts are pre DRF 3.0 I think and I'm not sure this is still the recommended way. Plus, the biggest question in my mind is:

Why is the marketplace object getting correctly serialized but the others are not? I would think that either all or none would be handled that way.

Verbal_Kint
  • 1,366
  • 3
  • 19
  • 35

0 Answers0