I have a set of django models and serializers that look like
class Role(models.Model):
guid = models.UUIDField(primary_key=True)
name = models.CharField(max_length=64, null=False)
class Login(models.Model):
guid = models.UUIDField(primary_key=True)
email = models.EmailField(null=False)
password = models.CharField(max_length=256, null=False)
class LoginRole(models.Model):
guid = models.UUIDField(primary_key=True)
login_guid = models.ForeignKey(Login, on_delete=models.PROTECT, db_column
="login_guid")
role_guid = models.ForeignKey(Role, on_delete=models.PROTECT, db_column=
"role_guid")
class Meta:
unique_together =('login_guid','role_guid')
class RoleSerializer(serializers.ModelSerializer):
guid = serializers.UUIDField(required=False, allow_null=True)
name = serializers.CharField(required=False, allow_null=True)
class Meta:
model = Role
fields ='__all__'
class LoginSerializer(serializers.ModelSerializer):
guid = serializers.UUIDField(required=False, allow_null=True)
email = serializers.EmailField(required=False, allow_null=True)
password = serializers.CharField(required=False, allow_null=True)
class Meta:
model = Login
fields = '__all__'
depth = 1
class LoginRoleSerializer(serializer.ModelSerializer):
guid = serializers.UUIDField(required=False, allow_null=True)
login_guid = LoginSerializer(required=False, allow_null=True)
role_guid = RoleSerializer(required=False, allow_null=True)
class Meta:
model = LoginRole
fields = '__all__'
def create(self, validated_data):
g = uuid.uuid4()
if 'login_guid' in validated_data:
login_data = validated_data.pop('login_guid')
try:
l = Login.objects.get(**login_data)
except (Login.DoesNotExist, Login.MultipleObjectsReturned,
IntegrityError):
return None
if 'role_guid' in validated_data:
role_data = validated_data.pop('role_guid')
try:
r = Role.objects.get(**role_data)
except (Role.DoesNotExist, Role.MultipleObjectsReturned,
IntegrityError):
return None
return LoginRole.objects.create(guid=g, login_guid=l, role_guid=r)
Now when I exercise a manage.py shell and issue the following commands I
trigger non_field_errors as shown.
>>> myd = { "login_guid": { "guid": '8e5f0ffa-8e87-481a-a3e4-3ba7b28253d0'
}, "role_guid": { "guid": 'df21d11f-10ea-4584-80b8-6fe5558c147c'}}
>>> ser = LoginRoleSerializer(data=myd)
>>> ser.is_valid()
False
>>> ser.errors
{'non_field_errors': ["'OrderedDict([('guid',
UUID('8e5f0ffa-8e87-481a-a3e4-3ba7b28253d0'))])' is not a valid UUID."]}
If I add
validators = []
to the Meta class of the LoginRoleSerializer, everything in the manage.py
shell works fine as the UniqueTogetherValidator (derived from the LoginRole
class) is removed from the Serializer
So that is my workaround for right now. I know the DRF docs state that this
is the case (see DRF Docs -- Optional Fields
<http://www.django-rest-framework.org/api-guide/validators/#optional-fields>)
but I am puzzled by why
1) it comes up as a "non_field_error" rather than a UniqueTogetherValidator
error
2) given the closed issue report
at https://github.com/encode/django-rest-framework/issues/2547 stating that
the serializer needs to
The reason here is that we need to know the value that is being passed to
the field at the point of the serializer in order to validate it. If you
added the field explicitly on the serializer with default='' then you'll
get the behavior you want.
Regarding #2, shouldn't the serializer evaluate UniqueTogether only after
the individual component fields have been evaluated? It seems like it is
firing prematurely.
Thanks in advance for any insight. Does it not work in the case of nested
serialziers because it cannot establish the Role and Login Instances until
the create() method of the LoginRoleSerializer? Could this be addressed, a
deferred validator?
--
You received this message because you are subscribed to the Google Groups
"Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.