Skip to content

Support violation_error_code and violation_error_message from UniqueConstraint in UniqueTogetherValidator#9766

Merged
auvipy merged 3 commits into
encode:mainfrom
s-aleshin:support-custom-error-unique-validator
Oct 9, 2025
Merged

Support violation_error_code and violation_error_message from UniqueConstraint in UniqueTogetherValidator#9766
auvipy merged 3 commits into
encode:mainfrom
s-aleshin:support-custom-error-unique-validator

Conversation

@s-aleshin

Copy link
Copy Markdown
Contributor

Added support for retrieving custom violation_error_code (for django 5+) and violation_error_message from Django model-level UniqueConstraint definitions and passing them to UniqueTogetherValidator.

refs #9714 and #9352

The update ensures that:
• If violation_error_message or violation_error_code are explicitly defined on the model constraint, they are forwarded to the corresponding validator.
• If the constraint uses the default message/code, they are not passed, allowing the validator to use its own defaults.

Additionally, tests have been added to cover both scenarios:
• When a custom error message/code is used.
• When defaults are applied.

Note: The current structure of get_unique_together_constraints() may benefit from refactoring (e.g., returning a named structure for clarity and extensibility). This is outside the scope of this PR, but I may explore it in a future contribution.

Comment thread rest_framework/serializers.py Outdated
@peterthomassen

Copy link
Copy Markdown
Collaborator

• If the constraint uses the default message/code, they are not passed, allowing the validator to use its own defaults.

What's the use case for that? (Why not use model-level default?)

…ture

Extracted error message logic to a separate method.

fix: conditionally include violation_error_code for Django >= 5.0

fix(validators): use custom error message and code from model constraints
@s-aleshin s-aleshin force-pushed the support-custom-error-unique-validator branch from 24e69af to c54c658 Compare August 18, 2025 14:41
@s-aleshin

Copy link
Copy Markdown
Contributor Author

• If the constraint uses the default message/code, they are not passed, allowing the validator to use its own defaults.

What's the use case for that? (Why not use model-level default?)

Returning the constraint’s default message would change the output and might break users relying on the validator’s default message—for example, in tests or UI rendering. I consider that the current behaviour should be maintained.

@peterthomassen peterthomassen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall, just minor questions!

Comment thread rest_framework/serializers.py Outdated
Comment thread rest_framework/validators.py
Comment thread tests/test_validators.py
peterthomassen
peterthomassen previously approved these changes Aug 20, 2025

@peterthomassen peterthomassen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm! Let's wait for @browniebroke's comment on the open conversation and then we're done!

@s-aleshin

Copy link
Copy Markdown
Contributor Author

lgtm! Let's wait for @browniebroke's comment on the open conversation and then we're done!

Hi @browniebroke! Just a quick ping in case this got lost — would be great to get your review when you have time.

@browniebroke

Copy link
Copy Markdown
Member

Just a quick ping in case this got lost — would be great to get your review when you have time.

Thanks for the patience and pinging again, I indeed missed that. Will try to take a look this week

@browniebroke browniebroke added this to the 3.17 milestone Sep 7, 2025
@browniebroke

Copy link
Copy Markdown
Member

That looks good to me. Will have to wait a bit for merging at we are working out the next version to release (3.16.2 or 3.17) and when.

Thanks for your patience

browniebroke
browniebroke previously approved these changes Sep 20, 2025
@auvipy auvipy requested review from Copilot and removed request for kevin-brown September 20, 2025 12:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 adds support for custom violation error codes and messages from Django model-level UniqueConstraint definitions to be passed through to UniqueTogetherValidator in Django REST Framework serializers.

  • Enhanced UniqueTogetherValidator to accept and use custom error codes and messages
  • Updated serializer logic to extract custom violation messages and codes from UniqueConstraint objects
  • Added comprehensive test coverage for both custom and default error handling scenarios

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
rest_framework/validators.py Enhanced UniqueTogetherValidator with code parameter support and updated error handling
rest_framework/serializers.py Added constraint lookup logic and violation message extraction to pass custom codes/messages to validators
tests/test_validators.py Added test model and test cases to verify custom and default error message/code behavior

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment thread rest_framework/serializers.py
Comment thread tests/test_validators.py
@s-aleshin s-aleshin dismissed stale reviews from browniebroke and peterthomassen via ea44b67 October 1, 2025 16:32

@peterthomassen peterthomassen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm!

@browniebroke browniebroke changed the title Support violation_error_code and violation_error_message from UniqueConstraint in UniqueTogetherValidator Support violation_error_code and violation_error_message from UniqueConstraint in UniqueTogetherValidator Oct 9, 2025
@auvipy auvipy merged commit 9cf6efb into encode:main Oct 9, 2025
7 checks passed
chandrasekharan-zipstack added a commit to Zipstack/unstract that referenced this pull request Jun 24, 2026
* [FIX] Re-bump djangorestframework 3.14.0 -> 3.17.1

Re-attempts the DRF upgrade reverted in #2098. 3.17.1 is chosen because it:
- carries PR encode/django-rest-framework#9766 (3.17.0), so the auto
  UniqueTogetherValidator honors a UniqueConstraint's violation_error_message
  for friendly duplicate messages (used by cloud-side create-only serializers),
- includes the CVE-2024-21520 (XSS) fix first shipped in 3.15.2.

Safe to layer on top of the Meta.validators=[] changes in the parent commit,
which neutralize the 3.15+ auto-validator for every upsert / IntegrityError-catch
serializer. Django 4.2.30 + Python 3.12 satisfy DRF 3.17's floors.

MUST be build + test + staging validated before merge (this bump caused the
rc.343 regression). drf-yasg 1.21.7 / drf-standardized-errors compatibility with
DRF 3.17 to be verified in CI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G8hAHc4HUo42zY1g9LAjKu

* [FIX] Remove unused hook-check-django-migrations dep group

Group had no consumer (migration check runs in backend env); its pinned
drf-yasg==1.21.7 paired with DRF 3.17.1 in the root lock was an incompatible
skew. Drop the group and relock.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G8hAHc4HUo42zY1g9LAjKu

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
chandrasekharan-zipstack added a commit to Zipstack/unstract that referenced this pull request Jun 24, 2026
…auto UniqueTogetherValidator on upsert/catch serializers (#2104)

* [FIX] Drop DRF auto UniqueTogetherValidator on upsert/catch serializers

DRF 3.15+ auto-generates a UniqueTogetherValidator from each model's
Meta.constraints UniqueConstraint. For serializers whose view already owns
uniqueness (upsert via update_or_create, or IntegrityError->Duplicate catch),
that validator fires at is_valid() and 400s on a legitimate re-save before the
view can run, short-circuiting the view's duplicate handling.

Set Meta.validators = [] on those serializers so the view/DB own uniqueness.
No-op on the currently-pinned DRF 3.14 (which only auto-validates legacy
unique_together); required once DRF is re-bumped to 3.17.x.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G8hAHc4HUo42zY1g9LAjKu

* [FIX] Re-bump djangorestframework 3.14.0 → 3.17.1 (#2105)

* [FIX] Re-bump djangorestframework 3.14.0 -> 3.17.1

Re-attempts the DRF upgrade reverted in #2098. 3.17.1 is chosen because it:
- carries PR encode/django-rest-framework#9766 (3.17.0), so the auto
  UniqueTogetherValidator honors a UniqueConstraint's violation_error_message
  for friendly duplicate messages (used by cloud-side create-only serializers),
- includes the CVE-2024-21520 (XSS) fix first shipped in 3.15.2.

Safe to layer on top of the Meta.validators=[] changes in the parent commit,
which neutralize the 3.15+ auto-validator for every upsert / IntegrityError-catch
serializer. Django 4.2.30 + Python 3.12 satisfy DRF 3.17's floors.

MUST be build + test + staging validated before merge (this bump caused the
rc.343 regression). drf-yasg 1.21.7 / drf-standardized-errors compatibility with
DRF 3.17 to be verified in CI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G8hAHc4HUo42zY1g9LAjKu

* [FIX] Remove unused hook-check-django-migrations dep group

Group had no consumer (migration check runs in backend env); its pinned
drf-yasg==1.21.7 paired with DRF 3.17.1 in the root lock was an incompatible
skew. Drop the group and relock.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G8hAHc4HUo42zY1g9LAjKu

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants