1
0
mirror of https://github.com/django/django.git synced 2025-10-24 06:06:09 +00:00

Fixed #16192 -- Made unique error messages in ModelForm customizable.

Overriding the error messages now works for both unique fields, unique_together
and unique_for_date.

This patch changed the overriding logic to allow customizing NON_FIELD_ERRORS
since previously only fields' errors were customizable.

Refs #20199.

Thanks leahculver for the suggestion.
This commit is contained in:
Loic Bistuer
2014-02-04 01:31:27 +07:00
committed by Tim Graham
parent 65131911db
commit 8847a0c601
11 changed files with 142 additions and 34 deletions

View File

@@ -941,36 +941,52 @@ class Model(six.with_metaclass(ModelBase)):
)
return errors
def date_error_message(self, lookup_type, field, unique_for):
def date_error_message(self, lookup_type, field_name, unique_for):
opts = self._meta
return _("%(field_name)s must be unique for %(date_field)s %(lookup)s.") % {
'field_name': six.text_type(capfirst(opts.get_field(field).verbose_name)),
'date_field': six.text_type(capfirst(opts.get_field(unique_for).verbose_name)),
'lookup': lookup_type,
}
field = opts.get_field(field_name)
return ValidationError(
message=field.error_messages['unique_for_date'],
code='unique_for_date',
params={
'model': self,
'model_name': six.text_type(capfirst(opts.verbose_name)),
'lookup_type': lookup_type,
'field': field_name,
'field_label': six.text_type(capfirst(field.verbose_name)),
'date_field': unique_for,
'date_field_label': six.text_type(capfirst(opts.get_field(unique_for).verbose_name)),
}
)
def unique_error_message(self, model_class, unique_check):
opts = model_class._meta
model_name = capfirst(opts.verbose_name)
params = {
'model': self,
'model_class': model_class,
'model_name': six.text_type(capfirst(opts.verbose_name)),
'unique_check': unique_check,
}
# A unique field
if len(unique_check) == 1:
field_name = unique_check[0]
field = opts.get_field(field_name)
field_label = capfirst(field.verbose_name)
# Insert the error into the error dict, very sneaky
return field.error_messages['unique'] % {
'model_name': six.text_type(model_name),
'field_label': six.text_type(field_label)
}
field = opts.get_field(unique_check[0])
params['field_label'] = six.text_type(capfirst(field.verbose_name))
return ValidationError(
message=field.error_messages['unique'],
code='unique',
params=params,
)
# unique_together
else:
field_labels = [capfirst(opts.get_field(f).verbose_name) for f in unique_check]
field_labels = get_text_list(field_labels, _('and'))
return _("%(model_name)s with this %(field_label)s already exists.") % {
'model_name': six.text_type(model_name),
'field_label': six.text_type(field_labels)
}
params['field_labels'] = six.text_type(get_text_list(field_labels, _('and')))
return ValidationError(
message=_("%(model_name)s with this %(field_labels)s already exists."),
code='unique_together',
params=params,
)
def full_clean(self, exclude=None, validate_unique=True):
"""

View File

@@ -105,6 +105,8 @@ class Field(RegisterLookupMixin):
'blank': _('This field cannot be blank.'),
'unique': _('%(model_name)s with this %(field_label)s '
'already exists.'),
'unique_for_date': _("%(field_label)s must be unique for "
"%(date_field_label)s %(lookup_type)s."),
}
class_lookups = default_lookups.copy()

View File

@@ -8,7 +8,7 @@ from collections import OrderedDict
import copy
import warnings
from django.core.exceptions import ValidationError
from django.core.exceptions import ValidationError, NON_FIELD_ERRORS
from django.forms.fields import Field, FileField
from django.forms.utils import flatatt, ErrorDict, ErrorList
from django.forms.widgets import Media, MediaDefiningClass, TextInput, Textarea
@@ -21,8 +21,6 @@ from django.utils import six
__all__ = ('BaseForm', 'Form')
NON_FIELD_ERRORS = '__all__'
def pretty_name(name):
"""Converts 'first_name' to 'First name'"""

View File

@@ -373,15 +373,21 @@ class BaseModelForm(BaseForm):
def _update_errors(self, errors):
# Override any validation error messages defined at the model level
# with those defined on the form fields.
# with those defined at the form level.
opts = self._meta
for field, messages in errors.error_dict.items():
if field not in self.fields:
if (field == NON_FIELD_ERRORS and opts.error_messages and
NON_FIELD_ERRORS in opts.error_messages):
error_messages = opts.error_messages[NON_FIELD_ERRORS]
elif field in self.fields:
error_messages = self.fields[field].error_messages
else:
continue
field = self.fields[field]
for message in messages:
if (isinstance(message, ValidationError) and
message.code in field.error_messages):
message.message = field.error_messages[message.code]
message.code in error_messages):
message.message = error_messages[message.code]
self.add_error(None, errors)