-
-
Notifications
You must be signed in to change notification settings - Fork 7k
UniqueTogheterValidator fails with partial unique indexes with ForeignKey #9779
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,7 @@ | |
|
|
||
| import pytest | ||
| from django import VERSION as django_version | ||
| from django.core.exceptions import ValidationError as DjangoValidationError | ||
| from django.db import DataError, models | ||
| from django.test import TestCase | ||
|
|
||
|
|
@@ -830,6 +831,75 @@ def test_unique_constraint_default_message_code(self): | |
| assert serializer.errors["non_field_errors"][0].code == UniqueTogetherValidator.code | ||
|
|
||
|
|
||
| class UniqueConstraintWithRelationModel(models.Model): | ||
| value = models.IntegerField() | ||
| first_related = models.ForeignKey(IntegerFieldModel, related_name='+', on_delete=models.CASCADE, null=True, blank=True) | ||
| second_related = models.ForeignKey(IntegerFieldModel, related_name='+', on_delete=models.CASCADE, null=True, blank=True) | ||
|
|
||
| class Meta: | ||
| constraints = [ | ||
| models.UniqueConstraint(fields=('value', 'first_related'), condition=models.Q(second_related__isnull=True), name='unique_constraint_with_relationa'), | ||
| models.UniqueConstraint(fields=('value', 'second_related'), condition=models.Q(first_related__isnull=True), name='unique_constraint_with_relationb'), | ||
|
||
| ] | ||
|
|
||
|
|
||
| class UniqueConstraintWithRelationModelSerializer(serializers.ModelSerializer): | ||
| class Meta: | ||
| model = UniqueConstraintWithRelationModel | ||
| fields = '__all__' | ||
|
|
||
|
|
||
| class TestUniqueConstraintWithRelationValidation(TestCase): | ||
| def setUp(self): | ||
| self.related_model = IntegerFieldModel.objects.create(integer=1) | ||
| self.instance_first = UniqueConstraintWithRelationModel.objects.create( | ||
| value=1, | ||
| first_related=self.related_model, | ||
| second_related=None | ||
| ) | ||
| self.instance_second = UniqueConstraintWithRelationModel.objects.create( | ||
| value=1, | ||
| first_related=None, | ||
| second_related=self.related_model | ||
| ) | ||
|
|
||
| def test_unique_constraint_with_relation_first(self): | ||
| instance = UniqueConstraintWithRelationModel(value=1, first_related=self.related_model, second_related=None) | ||
| with pytest.raises(DjangoValidationError) as excinfo: | ||
| instance.validate_constraints() | ||
|
|
||
| assert str(excinfo.value) == "{'__all__': ['Constraint “unique_constraint_with_relationa” is violated.']}" | ||
| serializer = UniqueConstraintWithRelationModelSerializer(data={ | ||
| 'value': 1, | ||
| 'first_related': self.related_model.pk, | ||
| 'second_related': None | ||
| }) | ||
| assert not serializer.is_valid() | ||
| assert serializer.errors == { | ||
| 'non_field_errors': [ | ||
| 'The fields value, first_related must make a unique set.' | ||
| ] | ||
| } | ||
|
|
||
| def test_unique_constraint_with_relation_second(self): | ||
| instance = UniqueConstraintWithRelationModel(value=1, second_related=self.related_model, first_related=None) | ||
| with pytest.raises(DjangoValidationError) as excinfo: | ||
| instance.validate_constraints() | ||
|
|
||
| assert str(excinfo.value) == "{'__all__': ['Constraint “unique_constraint_with_relationb” is violated.']}" | ||
| serializer = UniqueConstraintWithRelationModelSerializer(data={ | ||
| 'value': 1, | ||
| 'first_related': None, | ||
| 'second_related': self.related_model.pk | ||
| }) | ||
| assert not serializer.is_valid() | ||
| assert serializer.errors == { | ||
| 'non_field_errors': [ | ||
| 'The fields value, second_related must make a unique set.' | ||
| ] | ||
| } | ||
|
Comment on lines
+852
to
+900
|
||
|
|
||
|
|
||
| # Tests for `UniqueForDateValidator` | ||
| # ---------------------------------- | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The constraint name 'unique_constraint_with_relationa' appears to be truncated or missing an underscore. Based on Django naming conventions and the pattern in line 791 ('unique_constraint_with_relationb'), this should likely be 'unique_constraint_with_relation_a' or extend to something more descriptive like 'unique_constraint_with_relation_first'.