| | 41 | |
| | 42 | Maybe all unique constraints should allow raising validation error for specific field like ? |
| | 43 | |
| | 44 | |
| | 45 | {{{ |
| | 46 | |
| | 47 | from django.core.exceptions import ValidationError |
| | 48 | from django.db import models |
| | 49 | |
| | 50 | |
| | 51 | class ViolationFieldNameMixin: |
| | 52 | """ |
| | 53 | Mixin for BaseConstraint subclasses that builds custom |
| | 54 | ValidationError message for the `violation_field_name`. |
| | 55 | By this way we can bind the error to the field that caused it. |
| | 56 | This is useful in ModelForms where we can display the error |
| | 57 | message next to the field and also avoid displaying unique |
| | 58 | constraint violation error messages more than once for the same field. |
| | 59 | """ |
| | 60 | |
| | 61 | def __init__(self, *args, **kwargs): |
| | 62 | self.violation_field_name = kwargs.pop("violation_field_name", None) |
| | 63 | self.violation_code = kwargs.pop("violation_code", None) |
| | 64 | super().__init__(*args, **kwargs) |
| | 65 | |
| | 66 | def validate(self, *args, **kwargs): |
| | 67 | try: |
| | 68 | value = super().validate(*args, **kwargs) |
| | 69 | except ValidationError as e: |
| | 70 | # Create a new ValidationError with the violation_field_name attribute as the key |
| | 71 | e = ValidationError({self.violation_field_name: e}) |
| | 72 | # Set the error code to None |
| | 73 | # See https://code.djangoproject.com/ticket/34319#ticket |
| | 74 | e.code = self.violation_code |
| | 75 | raise e |
| | 76 | return value |
| | 77 | |
| | 78 | def deconstruct(self): |
| | 79 | path, args, kwargs = super().deconstruct() |
| | 80 | kwargs["violation_field_name"] = self.violation_field_name |
| | 81 | kwargs["violation_code"] = self.violation_code |
| | 82 | return path, args, kwargs |
| | 83 | |
| | 84 | def __eq__(self, other): |
| | 85 | return ( |
| | 86 | super().__eq__(other) |
| | 87 | and self.violation_field_name == getattr(other, "violation_field_name", None) |
| | 88 | and self.violation_code == getattr(other, "violation_code", None) |
| | 89 | ) |
| | 90 | |
| | 91 | |
| | 92 | class UniqueConstraint(ViolationFieldNameMixin, models.UniqueConstraint): |
| | 93 | ... |
| | 94 | |
| | 95 | }}} |
| | 96 | |