-
-
Notifications
You must be signed in to change notification settings - Fork 7k
chore: correctly validate unique constraints with distinct condition fields #9744
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?
chore: correctly validate unique constraints with distinct condition fields #9744
Conversation
…ogether validator
for unique_together in parent_class._meta.unique_together: | ||
yield unique_together, model._default_manager, [], None | ||
for constraint in parent_class._meta.constraints: | ||
if isinstance(constraint, models.UniqueConstraint) and len(constraint.fields) > 1: |
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.
do this need to be removed?
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.
We're now including the condition fields as part of the applicable fields that contribute to this count below. If we kept this here the condition fields would not be considered, which we need for this fix.
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.
Shouldn't there be a distinction made between condition fields and constraint fields here?
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.
We could split out the logic for clarity to require >1 constraint fields or 1 constraint field and 1+ condition fields distinct from the constraint field. Practically that would be the same however.
If you want to split our unique together constraints with a single constraint field and distinct condition fields into a new method, that would require a larger refactor of the existing constraint validation code.
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.
Pull Request Overview
This PR updates DRF’s validation to correctly treat single-field UniqueConstraint entries with additional condition fields as unique-together validations rather than per-field UniqueValidators.
- Extend unique-together detection to include UniqueConstraint with one field when the condition references other fields.
- Adjust field-level UniqueValidator generation to only apply when no additional condition fields are referenced.
- Add tests covering condition-based unique-together behavior.
Reviewed Changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
File | Description |
---|---|
tests/test_validators.py | Adds a model, serializer, and tests for condition-based unique-together validation; updates expectations for single-field UniqueConstraint behavior. |
rest_framework/utils/field_mapping.py | Imports helper and changes logic to only create UniqueValidator when the union of fields and condition fields is a single field. |
rest_framework/serializers.py | Updates unique-together constraint discovery to include single-field UniqueConstraints when conditions reference additional fields. |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
ConditionUniquenessTogetherModel.objects.create(race_name='example', position=1) | ||
|
||
data = {'race_name': 'example', 'position': 0} | ||
serializer = ConditionUniquenessTogetherSerializer(self.instance, data=data) |
Copilot
AI
Oct 16, 2025
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 serializer under test is passed an instance of UniquenessTogetherModel (self.instance) instead of ConditionUniquenessTogetherModel. This will cause the update validation to target the wrong model. Capture and pass the instance of ConditionUniquenessTogetherModel created in this test.
ConditionUniquenessTogetherModel.objects.create(race_name='example', position=1) | |
data = {'race_name': 'example', 'position': 0} | |
serializer = ConditionUniquenessTogetherSerializer(self.instance, data=data) | |
instance = ConditionUniquenessTogetherModel.objects.create(race_name='example', position=1) | |
data = {'race_name': 'example', 'position': 0} | |
serializer = ConditionUniquenessTogetherSerializer(instance, data=data) |
Copilot uses AI. Check for mistakes.
Failing unique together validation should result in non field errors when a condition-based | ||
unique together constraint is violated. |
Copilot
AI
Oct 16, 2025
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.
Hyphenate 'non-field errors' for correctness and consistency with DRF terminology.
Copilot uses AI. Check for mistakes.
Description
Resolves: #9707.