Django: как переопределить сообщение об ошибке unique_together?

В классе модели Meta я определяю unique_together. У меня есть ModelForm, основанный на этой модели. Когда я вызываю is_valid в этом ModelForm, ошибка будет автоматически повышаться, если проверка unique_together завершается с ошибкой. Это все хорошо.

Теперь моя проблема в том, что меня не устраивает сообщение об ошибке unique_together по умолчанию. Я хочу переопределить его. Как я могу это сделать? Для связанной с полем ошибки я легко могу это сделать, установив error_messages на параметры поля. Но unique_together - это полевая ошибка. Как я могу переопределить сообщение об ошибке без полей?

Ответы

Ответ 1

Вы можете сделать this в Django 1.7

from django.forms import ModelForm
from django.core.exceptions import NON_FIELD_ERRORS

class ArticleForm(ModelForm):
    class Meta:
        error_messages = {
            NON_FIELD_ERRORS: {
                'unique_together': "%(model_name)s %(field_labels)s are not unique.",
            }
        }

Ответ 2

Обновление 2016/10/20: см. jifeng-yin еще более приятный ответ ниже для Django >= 1.7

Самый лучший способ переопределить эти сообщения об ошибках - это переопределить метод unique_error_message на вашей модели. Django вызывает этот метод, чтобы получить сообщение об ошибке всякий раз, когда он сталкивается с проблемой уникальности во время проверки.

Вы можете просто обработать конкретный случай, который хотите, и разрешить всем другим делам Django, как обычно:

def unique_error_message(self, model_class, unique_check):
    if model_class == type(self) and unique_check == ('field1', 'field2'):
        return 'My custom error message'
    else:
        return super(Project, self).unique_error_message(model_class, unique_check)

Ответ 3

После быстрой проверки кажется, что ошибки проверки unique_together жестко закодированы в django.db.models.Model.unique_error_message:

def unique_error_message(self, model_class, unique_check):
    opts = model_class._meta
    model_name = capfirst(opts.verbose_name)

    # A unique field
    if len(unique_check) == 1:
        field_name = unique_check[0]
        field_label = capfirst(opts.get_field(field_name).verbose_name)
        # Insert the error into the error dict, very sneaky
        return _(u"%(model_name)s with this %(field_label)s already exists.") %  {
            'model_name': unicode(model_name),
            'field_label': unicode(field_label)
        }
    # unique_together
    else:
        field_labels = map(lambda f: capfirst(opts.get_field(f).verbose_name), unique_check)
        field_labels = get_text_list(field_labels, _('and'))
        return _(u"%(model_name)s with this %(field_label)s already exists.") %  {
            'model_name': unicode(model_name),
            'field_label': unicode(field_labels)
        }

Так что, возможно, вы должны попытаться переопределить этот метод из своей модели, чтобы вставить свое собственное сообщение!?

Однако я не пробовал, и это кажется довольно жестоким решением! Но если у вас нет чего-то лучшего, вы можете попробовать...

Ответ 4

Примечание: С этого ответа многое изменилось в Django. Поэтому лучше проверьте другие ответы...

Если какой sebpiq является истинным (поскольку я не проверяю исходный код), тогда есть один возможное решение, которое вы можете сделать, но это трудный путь...

Вы можете определить правило проверки в своей форме, как описано здесь

Вы можете увидеть примеры проверки с несколькими полями, поэтому, используя этот метод, вы можете определить уникальную проверку вместе перед стандартным django уникальная проверка выполнена...

Или худший, вы можете сделать валидацию в своем представлении, прежде чем пытаться сохранить объекты...

Ответ 5

Вы можете взглянуть на переопределение django/db/models/base.py: Model._perform_unique_checks() в вашей модели.

В этом методе вы можете получить "оригинальные" ошибки:

    errors = super(MyModel, self)._perform_unique_checks(unique_checks)

- затем измените и верните их вверх.