I have a case like this, where you have a custom nested serializer relation with a unique field. Sample case:
class GenreSerializer(serializers.ModelSerializer):
class Meta:
fields = ('name',) #This field is unique
model = Genre
class BookSerializer(serializers.ModelSerializer):
genre = GenreSerializer()
class Meta:
model = Book
fields = ('name', 'genre')
def create(self, validated_data):
genre = validated_data.pop('genre')
genre = Genre.objects.get(**genre)
return Book.objects.create(genre=genre, **validated_data)
The problem: When i try to save a json object like {"name":"The Prince", "genre": {"name": "History"}} DRF try to validate the genre object unique constraint and if "History" exists throw me an exception because a genre with name "History" must be unique, and that's true but i just trying to relate the object and not create together.
Thank you a lot!!
You should drop the unique validator for the nested serializer:
class GenreSerializer(serializers.ModelSerializer):
class Meta:
fields = ('name',) #This field is unique
model = Genre
extra_kwargs = {
'name': {'validators': []},
}
You may want to print your serializer before to make sure you don't have other validators on that field. If you have some, you'll have to include them in the list.
Edit: If you need to ensure the uniqueness constraint for creation, you should do it in the view after the serializer.is_valid
has been called and before serializer.save
.
This happens because the nested serializer (GenreSerializer
) needs an instance of the object to validate the unique constraint correctly (like put a exclude
clause to the queryset used on validation) and by default, a serializer will not pass the instance of related objects to fileds the are nested serializers when runs the to_internal_value()
method. See here
Another way to solve this problem is override the get_fields()
method on parent serializer and pass the instance of related object
class BookSerializer(serializers.ModelSerializer):
def get_fields(self):
fields = super(BookSerializer, self).get_fields()
try: # Handle DoesNotExist exceptions (you may need it)
if self.instance and self.instance.genre:
fields['genre'].instance = self.instance.genre
except Genre.DoesNotExist:
pass
return fields