1

I want to create nested objects with django-rest-framework serializers(drf).

Initially, I create such serializers:

class CollectionCreateSerializer(ModelSerializer):
   citizens = CitizenSerializer(many=True)

   ## Some definition of serializer fields


    def create(self, validated_data):
        collection = Collection.objects.create()
        citizens = validated_data.pop('citizens')

        for citizen in citizens:
            citizen_serializer = CitizenSerializer(data=citizen,
                                                   context={'citizens': citizens)
            citizen_serializer.is_valid(raise_exception=True)
            citizen_serializer.save()

        return collection

class CitizenSerializer(serializers.ModelSerializer):


   ## Some defenition of serializer fields



    def validate(self, attrs):
        print('in validate citizen')
        citizens = self.context['citizens']

        ## Some validation logic with citizens context

        return super().validate(attrs)

But that did not work, because validate method calls from create method, and before it when validation of collection happens. And the problem is that in the first case context contains 'request' and some other info. And in the second case context contains defined in create method context.

So validate method on each citizen called twice with different context info.

Then I tried to delete is_valid method from create method. And the next logical error occurred:

 You must call `.is_valid()` before calling `.save()`.

Then I tried to make citizens value real-only to prevent internal validation. But then the citizens field is not included in the validated data in the create method.

So I expect that some flag that turns off the internal nested objects validation? Or maybe a nicer solution exists.

1 Answer 1

2

The problem in your implementation is that you are creating a CitizenSerializer instance in your create method of your CollectionCreateSerializer.

You shouldn't do that because CitizenSerializer is defined as a nested-serializer field and therefore it is called and validated already when your CollectionCreateSerializer instance is created. See this example for detail.

You need to update your CollectionCreateSerializer such as:

class CollectionCreateSerializer(ModelSerializer):
   citizens = CitizenSerializer(many=True)

   ## Some definition of serializer fields


    def create(self, validated_data):
        collection = Collection.objects.create()

        citizens = validated_data.pop('citizens')
        for citizen in citizens:
            Citizen.objects.create(collection=collection, **citizen)

        return collection
Sign up to request clarification or add additional context in comments.

1 Comment

Yep, this is a solution. But I have some logic about deserialization of Citizen. So in this solution, I need to include that logic in CollectionSerializer. That does not seem perfect in this case.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.