Dealing with unique constraints in nested serializers.
This question comes pretty often on Stackoverflow /IRC / mailing list.
The issue is when one uses nested serializers while the nested model has a unique constraint. Here’s a
Task model that has a foreign key to a User:
Let’s build a serializer that nests a
Now -assuming we already have an admin user - if we create the following data:
we’re catching a unicity error:
HTTP 400 Bad Request
Allow: GET, POST, HEAD, OPTIONS
"A user with that username already exists."
Django REST framework adds a unicity constraint based on the model’s introspection. If we print the serializer, here’s what we’ll see:
id = IntegerField(label='ID', read_only=True)
owner = UserSerializer():
username = CharField(
<django.contrib.auth.validators.UnicodeUsernameValidator object>, <UniqueValidator(queryset=User.objects.all())>
name = CharField(max_length=128)
As you may notice, there’s a
UniqueSerializer on the owner’s username.
Since this is a nested serializer, there’s no way Django REST framework can know whether this object will be created or taken from the database. The create/update actions apply to the
TaskSerializer, not to the
UserSerializer. Therefore the
UniqueValidator will be applied for every request since we may either create the
User or update an existing one.
If we want to regain the control over it, we need to explicitly remove that validator:
From now on, the unicity over
Username will not be checked during validation. It’ll be up to us to deal with it whenever required — ie when we’ll need to create the nested resource.