-
-
Notifications
You must be signed in to change notification settings - Fork 6.9k
ModelSerializer UniqueTogetherValidator is incompatible with field source #7100
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
Comments
Why aren't your fields in a list? |
@napsterv it's equivalent to a tuple so it's fine anyway. |
@xordoquy that's entire traceback
It seems that the problem occurs when there is a unique_together in the meta class of the model. # models.py
class MyModel(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE
)
date_from = models.DateField()
date_to = models.DateField()
class Meta:
unique_together = (
('date_from', 'user'),
('date_to', 'user'),
) Corrected the original description. |
I'm having the same issue.
I can make my failing tests pass by replacing this with:
and similarly, in
I can't be 100% sure the different way of finding the fields doesn't break any assumptions about when the fields should be present. |
I'm getting the same issue with DRF 3.11 Serializer
Model
|
Thanks - I'll look into this. This stems from #7086, which fixed a related bug. It looks like those changes in turn broke For now, a workaround would be to declare the class MyModelSerializer(serializers.ModelSerializer):
date_start = serializers.DateField(source='date_from')
date_end = serializers.DateField(source='date_to')
class Meta:
model = MyModel
fields = ['date_start', 'date_end', 'user']
validators = [
UniqueTogetherValidator(queryset=MyModel.objects.all(), fields=['user', 'date_start']),
UniqueTogetherValidator(queryset=MyModel.objects.all(), fields=['user', 'date_end']),
] |
Hi all, just opened #7143. If you could test those changes to see if they fix the issue, any feedback would be appreciated. |
Hi @rpkilby! Your branch does not seem to fix the issue, at least with manually instantiated UniqueTogetherValidators. This is our test case (working well with DRF 3.10.3): from django.test import TestCase
from rest_framework import serializers
from rest_framework.validators import UniqueTogetherValidator
from app import models, factories
class MyNestedSerializer(serializers.Serializer):
object_ref = serializers.CharField(
source='customer_object_ref', max_length=64, required=False, allow_null=True,
)
class MySerializer(serializers.ModelSerializer):
customer = serializers.IntegerField(default=1)
customer_info = MyNestedSerializer(source='*', required=False)
class Meta:
model = models.MyObject
fields = ('customer', 'customer_info')
validators = [
UniqueTogetherValidator(
queryset=models.MyObject.objects.all(),
fields=('customer', 'customer_object_ref')
)
]
class DRFIssue(TestCase):
fixtures = []
def test_issue(self):
obj = factories.MyObjectFactory()
serializer = MySerializer(instance=obj, data={"customer_info": {"object_ref": "test"}})
self.assertTrue(serializer.is_valid()) This test fails even with your branch
This issue is breaking a lot of our code base as we have some of those UniqueTogetherValidator pretty much everywhere. |
@lerela Seems like you should try use serializer field name (not source model field name) in i.e. in your case this would probably be like this
Not sure if it'll work in your case, but in my case where I had
=> the following validator in
|
@cepbuch Note that |
Hi @lerela. As @cepbuch mentioned, the
Validating fields across a nested serializer was not intended to be supported and only worked due to the previous bug (validator incorrectly checked source model fields instead of serializer fields). That all said, I'm not entirely sure what to recommend. If possible, it would be best if you could move your nested serializer fields to their parent serializers, but I realize this may not be possible. An alternative would be to recreate the old |
Hi @rpkilby. This is a huge breaking change for us (but I understand that our code base makes use of an old loophole!) and it feels like it should at least be part of the 3.11 announcement (but maybe it'll be in the release notes when they are published). I'll need more time to assess the impact on our project as we cannot break public APIs and move the fields onto their parent serializers. I assume we'll have either to follow your advice with the old |
@rpkilby we observed the initial issue in addition to the undefined behavior I reported and I can confirm that your branch fixes it. |
@rpkilby I can confirm your branch fixes our use case, thanks! |
@rpkilby +1 |
@rpkilby +1
class UserRepo(models.Model):
user = models.ForeignKey('users.User', on_delete=models.CASCADE)
repo = models.ForeignKey(GitRepo, on_delete=models.CASCADE)
class Meta:
unique_together = (('user', 'repo'),)
class CreateUserRepoSerializer(serializers.ModelSerializer):
user_id = UserFilteredPrimaryKeyRelatedField(source='user')
repo_id = RepoFilteredPrimaryKeyRelatedField(source='repo')
class Meta:
model = UserRepo
fields = [
'user_id',
'repo_id',
]
validators = [
UniqueTogetherValidator(queryset=UserRepo.objects.all(), fields=['user_id', 'repo_id']),
] Then the Great. Perfect. |
Uh oh!
There was an error while loading. Please reload this page.
Checklist
master
branch of Django REST framework.Steps to reproduce
In DRF == 3.10.3 and below it was a valid case
In DRF == 3.11.0 I get an error in is_valid() method
This case is no longer valid?
It was a convenient way to redirect field names.
The text was updated successfully, but these errors were encountered: