Changes between Version 2 and Version 3 of Ticket #34319


Ignore:
Timestamp:
Feb 7, 2023, 4:27:18 PM (22 months ago)
Author:
Mateusz Kurowski
Comment:

Legend:

Unmodified
Added
Removed
Modified
  • Ticket #34319 – Description

    v2 v3  
    3939}}}
    4040
     41
     42Maybe all unique constraints should allow raising validation error for specific field like ?
     43
     44
     45{{{
     46
     47from django.core.exceptions import ValidationError
     48from django.db import models
     49
     50
     51class 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
     92class UniqueConstraint(ViolationFieldNameMixin, models.UniqueConstraint):
     93    ...
     94
     95}}}
     96
Back to Top