Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UniqueTogetherValidator does not work with source kwarg #9442

Open
3 of 6 tasks
r-thomson opened this issue Jun 19, 2024 · 1 comment
Open
3 of 6 tasks

UniqueTogetherValidator does not work with source kwarg #9442

r-thomson opened this issue Jun 19, 2024 · 1 comment

Comments

@r-thomson
Copy link

My team has run into a bug in UniqueTogetherValidator where it does not work properly with fields with the source attribute. If a field has a source that is different than the field's name on the serializer, then that field is effectively ignored when checking for uniqueness violations, and the ValidationError is not raised.

I am using a serializer set up like this. Note that UniqueTogetherValidator is expecting the serializer's name for the fields argument— you'll get an error on this line if you try to provide the source name instead.

class ExampleSerializer(serializers.Serializer):
    list_id = serializers.PrimaryKeyRelatedField(source='list')
    position = serializers.IntegerField(source='ordering_key')

    class Meta:
        validators = [
            UniqueTogetherValidator(
                queryset=ToDoItem.objects.all(),
                fields=['list_id', 'position']
            )
        ]

I believe the bug occurs at this position in the code:

else:
# Ignore validation if all field values are unchanged
checked_values = [
value
for field, value in attrs.items()
if field in self.fields and value != getattr(serializer.instance, field)
]
if checked_values and None not in checked_values and qs_exists(queryset):
field_names = ', '.join(self.fields)
message = self.message.format(field_names=field_names)
raise ValidationError(message, code='unique')

On line 172, we check if field (which comes from source) is in self.fields (which is the name on the serializer). If we're looking at the serializer above, then attrs.keys() would be ['list', 'ordering_key'] and self.fields is ['list_id', 'position'].

This means that checked_values will always be empty, and a ValidationError will never be raised.

Checklist

  • Raised initially as discussion #...
  • This is not a feature request suitable for implementation outside this project. Please elaborate what it is:
    • compatibility fix for new Django/Python version ...
    • other type of bug fix
    • other type of improvement that does not touch existing code or change existing behavior (e.g. wrapper for new Django field)
  • I have reduced the issue to the simplest possible case.

REST Framework version: 3.15.1

@r-thomson r-thomson changed the title UniqueTogetherValidator does not work with source attr UniqueTogetherValidator does not work with source kwarg Jun 19, 2024
@BPC-AnonymousBeast
Copy link

I tried to reproduce the same and I am able to get the expected results.
As per my understanding from whatever you have mentioned, you need to replace 'ToDoItem' with your Model class name in 'queryset=ToDoItem.objects.all(),'

My code : -

class PeopleSerialiser(serializers.Serializer):

name1 = serializers.CharField(source='name',required = True)
lastname = serializers.CharField(required = True)
age = serializers.IntegerField(required = False)

class Meta():        
    validators = [
        UniqueTogetherValidator(
            queryset=Person.objects.all(),
            fields=['name1', 'lastname']
        )
    ] 
 
 Note : its 'name' in my model class and its 'name1' in the serializer class. So, I have changed the field name.

Output :

{
"non_field_errors": [
"The fields name1, lastname must make a unique set."
]
}

The only limitation I see here is, it throws this error only when you try to post the names in the same order.
For ex: you have "John Doe" in your table and try to enter "John Doe " again, it will give you this error. It will accept another entry as "Doe John" while it should not accept. I'm not sure about my understanding of UniqueTogether. Someone can correct me if I'm wrong.

If this does not resolve your issue, please provide the code of your model class that you are trying to serialize. Also, specify the name of the model class. I'll dig deeper.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants