Django - Как указать, в каком поле не проходит проверка?

У меня есть эта модель, которую я показываю на странице администратора:

class Dog(models.Model):
    bark_volume = models.DecimalField(...
    unladen_speed = models.DecimalField(...

    def clean(self):
        if self.bark_volume < 5:
            raise ValidationError("must be louder!")

Как видите, я проверил модель. Но я хочу, чтобы страница администратора показывала ошибку рядом с полем bark_volume вместо общей ошибки, как сейчас. Есть ли способ указать, в каком поле происходит сбой проверки?

Большое спасибо заранее.


person Greg    schedule 13.06.2011    source источник


Ответы (6)


Хорошо, я понял из этого ответа.

Вам нужно сделать что-то вроде этого:

class Dog(models.Model):
    bark_volume = models.DecimalField(...
    unladen_speed = models.DecimalField(...

    def clean_fields(self):
        if self.bark_volume < 5:
            raise ValidationError({'bark_volume': ["Must be louder!",]})
person Greg    schedule 14.06.2011
comment
Если перевод не нужен, достаточно использовать строку для сообщения, список не требуется: raise ValidationError({'bark_volume': 'Must be louder!'}). Использование Django 1.9.5. - person arogachev; 29.04.2016

class Dog(models.Model):
    bark_volume = models.DecimalField(...
    unladen_speed = models.DecimalField(...

    def clean(self):
        if self.bark_volume < 5:
            if not self._errors.has_key('bark_volume'):
                from django.forms.util import ErrorList
                self._errors['bark_volume'] = ErrorList()
            self._errors['bark_volume'].append('must be louder!')

По крайней мере, это работает с формами. Никогда не пробовал на самой модели, но методика должна быть такой же. Однако из документов Django:

Когда вы используете ModelForm, вызов is_valid () выполнит эти шаги проверки для всех полей, включенных в форму. (Дополнительную информацию см. В документации ModelForm.) Вам нужно вызывать метод модели full_clean () только в том случае, если вы планируете самостоятельно обрабатывать ошибки проверки или если вы исключили из ModelForm поля, требующие проверки.

И...

Обратите внимание, что full_clean () не будет вызываться автоматически при вызове метода save () вашей модели или в результате проверки ModelForm. Вам нужно будет вызвать его вручную, если вы хотите запустить проверку модели вне ModelForm.

Итак, в основном, если у вас нет действительно веских причин для очистки поля в модели, вы должны вместо этого сделать это в форме. Код для этого будет выглядеть так:

class DogForm(forms.ModelForm):

    def clean(self):
        bark_volume = self.cleaned_data.get('bark_volume')
        if bark_volume < 5:
            if not self._errors.has_key('bark_volume'):
                from django.forms.util import ErrorList
                self._errors['bark_volume'] = ErrorList()
            self._errors['bark_volume'].append('must be louder!')

        return self.cleaned_data

И это наверняка сработает.

person Chris Pratt    schedule 13.06.2011
comment
Вам также нужно поднять ValidationError? или Django проверяет наличие self._errors после вызова чистого метода? - person Ted; 13.06.2011
comment
Фактически, повышение ValidationError просто добавляет элементы в self._errors. Это основной список всех ошибок в форме. - person Chris Pratt; 13.06.2011
comment
Использование его в модели дает мне эту ошибку: объект 'Dog' не имеет атрибута '_errors' - person Greg; 14.06.2011
comment
Хорошо, тогда может показаться, что вы не можете использовать ту же методологию. Я бы посоветовал провести проверку вашей формы, если она включает несколько полей. Этот метод будет работать с формами. - person Chris Pratt; 15.06.2011
comment
ни в результате проверки ModelForm. Это неправда или, по крайней мере, больше не правда. self.instance.instance.full_clean() вызывается в ModelForm._post_clean методе, который вызывается в ModelForm.is_valid. Эта цитата также была удалена из документации. - person RecursivelyIronic; 14.03.2015

Обратите внимание на тех, кто может столкнуться с этим с более новой версией Django - метод clean_fields из принятого ответа теперь требует параметра «exclude». Кроме того, я считаю, что в принятом ответе также отсутствует вызов его суперфункции. Последний код, который я использовал, был:

def clean_fields(self, exclude=None):
    super(Model, self).clean_fields(exclude)

    if self.field_name and not self.field_name_required:
        raise ValidationError({'field_name_required':["You selected a field, so field_name_required is required"]})
person streetlogics    schedule 04.04.2014
comment
Я думаю, что код проверки должен учитывать параметр exclude, поэтому такой вызов, как clean_fileds(model, exclude=["field_name"]), не вызывает исключения, даже если требуется field_name. - person firegurafiku; 21.07.2016

сокращенно из django docs:

def clean(self):
    data = self.cleaned_data
    subject = data.get("subject")

    if subject and "help" not in subject:
        msg = "Must put 'help' in subject."
        self.add_error('subject', msg)

    return data
person Chase    schedule 22.11.2017

Используйте метод clean_, специфичный для данного поля:

class DogForm(forms.ModelForm):
    class Meta:
        model = Dog

    def clean_bark_volume(self):
        if self.cleaned_data['bark_volume'] < 5:
            raise ValidationError("must be louder!")

См. clean<fieldname> часть страницы Проверка формы. Кроме того, не забудьте использовать cleaned_data вместо самого поля формы; у последних могут быть старые данные. Наконец, сделайте это на форме, а не на модели.

person Mike DeSimone    schedule 13.06.2011
comment
Во-первых, он использовал метод clean на модели, а не на форме. Итак, в этом сценарии нет cleaned_data. Во-вторых, clean_FOO применимо только в том случае, если вы проверяете только это конкретное поле. Если задействовано несколько полей, вы должны использовать clean - person Chris Pratt; 13.06.2011
comment
Может быть несколько clean_<fieldname> методов; каждый будет проверяться по очереди, и их ошибки будут прикреплены к соответствующим полям. - person Mike DeSimone; 14.06.2011
comment
Какое отношение это имеет? Вы не можете проверить несколько полей одним методом clean_ ‹fieldname›. Нет гарантии доступности cleaned_data для одного поля внутри чистого метода другого. Если ваша проверка включает несколько полей, вы должны использовать вместо них clean. - person Chris Pratt; 14.06.2011

Самый простой способ проверить этот конкретный случай:

from django.core.validators import MinValueValidator
from django.utils.translation import ugettext_lazy as _

class Dog(models.Model):
    bark_volume = models.DecimalField(
        ..., validators=[MinValueValidator(5, message=_("Must be louder!"))]

Документация Django о валидаторах: https://docs.djangoproject.com/en/dev/ref/validators/

person Monika Sulik    schedule 06.08.2012
comment
это идиоматическое решение :) - person robermorales; 08.10.2016
comment
Просто понял, что раньше у меня не было сообщения в решении, поэтому добавил его :) - person Monika Sulik; 20.10.2016