-
-
Notifications
You must be signed in to change notification settings - Fork 6.7k
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
ModelSerializer not generating validators for constraints #7173
Comments
Maybe here:
Need something like this: for constraint in self._meta.constraints:
if constraint is UniqueConstraint:
print(constraint.fields) |
Now that the docs recommend using constraints instead of @rpkilby Are you working on this? I see you assigned yourself... |
This really should've been handled automatically by DRF, and in the future, it will be. But for now, we need to have constraints both on the serializer (to get status code 400), and on the model (to prevent direct database constraint violations). See encode/django-rest-framework#7173
@dmwyatt I'm not currently working on this - haven't really had the time for larger open source contribution for a while. re: Assignment, it's not a strict ownership claim, more a signal to other maintainers that I'm interested. It also allows me to more easily find this issue later when I do have time to contribute. That is all to say, don't let my self-assigning the ticket stop you from opening your own PR. |
Any updates on this? |
Did anyone find a workaround? |
Since this seems like a desired feature I thought this django-developers post might be of interested to you https://groups.google.com/g/django-developers/c/iiOnxAn3vy4. If |
Got the same problem right now and did this as an easy workaround until it is fixed: Using the same example as in the issue: # models.py
class Foo(models.Model):
f1 = models.CharField(max_length=32)
f2 = models.IntegerField()
class Meta:
# unique_together = ('f1', 'f2')
constraints = [
models.UniqueConstraint(name='unique_foo', fields=[
'f1', 'f2'
])
]
# serializers.py
class FooSerializer(serializers.ModelSerializer):
def validate(self, data):
#this works great with POST, PUT but with PATCH you have to add extra logic since some fields are not presented and you should get it from `self.instance`
if Foo.objects.filter(f1=data['f1'], f2=data['f2']).exists():
raise serializers.ValidationError(
{'error': 'f1 and f2 should be unique together'})
return data
class Meta:
model = Foo
fields = '__all__' Still looking for any updates on this! UPDATE: |
You are running a query everytime the serializer is called, doesn't seem optimal performance-wise. I'd rather override the specific actions in the viewset (if you haven't done that already), and catch the IntegrityError in there. |
I think it's fine,
Good idea at first glance, but I'm afraid that it won't work for our case. |
any update on this issue? |
The issue lives on, just catching up with it! |
Support for I guess a |
While we are waiting for the update, you can try this method. What do you think? from rest_framework.validators import UniqueTogetherValidator
from rest_framework.exceptions import ValidationError
class CustomUniqueConstraintValidator(UniqueTogetherValidator):
def __init__(self, queryset, fields, instance, condition=None, message=None):
super().__init__(queryset, fields, message)
if condition is not None:
self.queryset = queryset.filter(condition)
self.instance = instance
class UniqueConstraintMixin(object):
def validate(self, attrs):
constraints = self.Meta.model._meta.constraints
errors = []
for constraint in constraints:
validator = CustomUniqueConstraintValidator(
queryset=self.Meta.model._default_manager,
fields=constraint.fields,
instance=self.instance,
condition=constraint.condition
)
try:
validator(attrs)
except ValidationError as exc:
errors.extend(exc.detail)
if errors:
raise ValidationError(errors)
return attrs
class FooSerializer(UniqueConstraintMixin, serializers.ModelSerializer):
class Meta:
model = Foo
fields = '__all__' |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
bump. This is a real issue. |
This gives a KeyError if one of the constraints is excluded on the serializer. |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
This is a real issue, please keep it open. |
primary support has been added on main branch. in future we should also look for additional new API's & django validation based simpler implementation when we are 4.1/4.2+ only |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
Please keep this open until a solution emerges |
you can check this for primary support #7438 |
no it will be part of 3.15 release, you can try from main branch |
It can be used the function on def enforce_required_fields(self, attrs, serializer):
"""
The `UniqueTogetherValidator` always forces an implied 'required'
state on the fields it applies to.
"""
if serializer.instance is not None:
return
missing_items = {
field_name: self.missing_message
for field_name in self.fields
if serializer.fields[field_name].source not in attrs
}
if missing_items:
raise ValidationError(missing_items, code='required') |
Thanks @auvipy @kalekseev for your hard works on this feature, I can't wait for release 3.15 to try it out. Another thought: Can we extend this further so that DRF Validators are compatible with CheckConstraint as well? |
Isnt that already working? |
Checklist
master
branch of Django REST framework.Steps to reproduce
Replacing
unique_together
on a model withUniqueConstraint
constraint (as per Django docs) results in.is_valid()
returningTrue
(and anIntegrityError
exception being thrown when a call to.save()
follows (or500 Internal Server Error
when using API)) rather than.is_valid()
returningFalse
(or400 Bad Request
when using API) when uniqueness is violated.Expected behavior
Expected same behavior as when using
unique_together
:When using, e.g., the browsable API, this results in a
400 Bad Request
.Actual behavior
When using, e.g., the browsable API, this results in a
500 Internal Server Error
.The text was updated successfully, but these errors were encountered: