Re: [Django] #34319: ValidationError handling during model.validate_constraints

2 views
Skip to first unread message

Django

unread,
Feb 7, 2023, 5:27:21 PM2/7/23
to django-...@googlegroups.com
#34319: ValidationError handling during model.validate_constraints
-------------------------------------+-------------------------------------
Reporter: Mateusz Kurowski | Owner: nobody
Type: | Status: new
Cleanup/optimization |
Component: Database layer | Version: 4.1
(models, ORM) |
Severity: Normal | Resolution:
Keywords: Model, | Triage Stage:
validate_constraints, | Unreviewed
ValidationError, code, message |
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Description changed by Mateusz Kurowski:

Old description:

> Imagine scenario when i want to explicitly mark a field that model
> constraint should raise ValidationError for:
>

> {{{
> class CustomUniqueConstraint(UniqueConstraint):
>
> def validate(self, *args, **kwargs):
> try:
> value = super().validate(*args, **kwargs)
> except ValidationError as e:
> raise ValidationError(
> {
> 'email': e,
> }
> )
> return value
>

> class AbstractUser(django.contrib.auth.models.AbstractUser):
>
> class Meta:
> abstract = True
> constraints = [
> CustomUniqueConstraint(
> Lower("email"),
> name="%(app_label)s_%(class)s_email_unique",
> )
> ]
> }}}
>

> This wont work because:
>
> {{{
> 1425, in validate_constraints
> if e.code == "unique" and len(constraint.fields) == 1:
> ^^^^^^
> AttributeError: 'ValidationError' object has no attribute 'code'
> }}}

New description:

Imagine scenario when i want to explicitly mark a field that model
constraint should raise ValidationError for:


{{{
class CustomUniqueConstraint(UniqueConstraint):

def validate(self, *args, **kwargs):
try:
value = super().validate(*args, **kwargs)
except ValidationError as e:
raise ValidationError(
{
'email': e,
}
)
return value


class AbstractUser(django.contrib.auth.models.AbstractUser):

class Meta:
abstract = True
constraints = [
CustomUniqueConstraint(
Lower("email"),
name="%(app_label)s_%(class)s_email_unique",
)
]
}}}


This wont work because:

{{{
1425, in validate_constraints
if e.code == "unique" and len(constraint.fields) == 1:
^^^^^^
AttributeError: 'ValidationError' object has no attribute 'code'
}}}


Maybe all unique constraints should allow raising validation error for
specific field like ?


{{{

from django.core.exceptions import ValidationError
from django.db import models


class ViolationFieldNameMixin:
"""
Mixin for BaseConstraint subclasses that builds custom
ValidationError message for the `violation_field_name`.
By this way we can bind the error to the field that caused it.
This is useful in ModelForms where we can display the error
message next to the field and also avoid displaying unique
constraint violation error messages more than once for the same
field.
"""

def __init__(self, *args, **kwargs):
self.violation_field_name = kwargs.pop("violation_field_name",
None)
self.violation_code = kwargs.pop("violation_code", None)
super().__init__(*args, **kwargs)

def validate(self, *args, **kwargs):
try:
value = super().validate(*args, **kwargs)
except ValidationError as e:
# Create a new ValidationError with the violation_field_name
attribute as the key
e = ValidationError({self.violation_field_name: e})
# Set the error code to None
# See https://code.djangoproject.com/ticket/34319#ticket
e.code = self.violation_code
raise e
return value

def deconstruct(self):
path, args, kwargs = super().deconstruct()
kwargs["violation_field_name"] = self.violation_field_name
kwargs["violation_code"] = self.violation_code
return path, args, kwargs

def __eq__(self, other):
return (
super().__eq__(other)
and self.violation_field_name == getattr(other,
"violation_field_name", None)
and self.violation_code == getattr(other,
"violation_code", None)
)


class UniqueConstraint(ViolationFieldNameMixin, models.UniqueConstraint):
...

}}}

--

--
Ticket URL: <https://code.djangoproject.com/ticket/34319#comment:3>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Feb 7, 2023, 5:36:39 PM2/7/23
to django-...@googlegroups.com

Old description:

> Maybe all unique constraints should allow raising validation error for
> specific field like ?
>

> class UniqueConstraint(ViolationFieldNameMixin, models.UniqueConstraint):
> ...
>
> }}}

New description:


{{{
class CustomUniqueConstraint(UniqueConstraint):


class AbstractUser(django.contrib.auth.models.AbstractUser):


This wont work because:


{{{

e.code = self.violation_code


class UniqueConstraint(ViolationFieldNameMixin, models.UniqueConstraint):
...

}}}

--

--
Ticket URL: <https://code.djangoproject.com/ticket/34319#comment:4>

Reply all
Reply to author
Forward
0 new messages