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.

Reply via email to