Reputation: 398
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.
Upvotes: 1
Views: 1401
Reputation: 1847
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
Upvotes: 2