Предлагают ли модели django что-то похожее на форму clean_‹fieldname›()?

Я пытаюсь перенести все проверки, связанные с бизнес-логикой, в модели, а не оставлять их в формах. Но здесь у меня есть каверзная ситуация, по поводу которой я люблю консультироваться с сообществом SO.

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

def clean_email(self):
    email = self.cleaned_data['email']

    if ExtendedUser.objects.filter(email=email).exists():
        raise ValidationError('This email address already exists.')
    return email

Если бы я перенес эту проверку на модели, согласно официальному документу, я бы поместил ее в clean() соответствующей модели, ExtendedUser. Но документ также упоминает следующее:

Любые исключения ValidationError, вызванные Model.clean(), будут храниться в специальном ключе словаря ошибок NON_FIELD_ERRORS, который используется для ошибок, связанных со всей моделью, а не с конкретным полем.

Это означает, что с clean() я не могу связать возникающие из него ошибки с конкретными полями. Мне было интересно, предлагают ли модели что-то похожее на формы clean_<fieldname>(). Если нет, то где бы вы разместили эту логику проверки и почему?


person tamakisquare    schedule 21.03.2012    source источник
comment
Разве эта логика не связана с формой? Как вы думаете, почему для него было бы лучше жить в модели? На мой взгляд, это было бы предполагаемым использованием моделей в django.   -  person vascop    schedule 22.03.2012
comment
@VascoP - я просто хочу централизовать всю свою бизнес-логику в моделях. Во-первых, он более организован с точки зрения дизайна. И концептуально, я думаю, имеет смысл проводить валидацию в моделях. Кроме того, у него есть преимущество в том, что он использует одну и ту же проверку, когда у меня есть несколько форм моделей, основанных на одной и той же модели.   -  person tamakisquare    schedule 22.03.2012
comment
Вы также можете наследовать от более общей формы модели, связанной с данной моделью, и иметь подмодели для каждой другой формы.   -  person vascop    schedule 22.03.2012
comment
@VascoP - мне нравится общий подход к форме модели. Пожалуйста, добавьте это к своему ответу, и я приму его. Ура~   -  person tamakisquare    schedule 24.03.2012
comment
Я отредактировал свой ответ, чтобы уточнить, что я имел в виду. Это то, что вы искали?   -  person vascop    schedule 24.03.2012


Ответы (2)


Вы можете преобразовать свой чистый метод в validator и включите его при объявлении поля.

Другой вариант — создать подкласс поля модели и переопределить его чистый метод.

Однако нет прямого эквивалента определения методов clean_<field name>, как это можно сделать для форм. Вы даже не можете назначать ошибки отдельным полям, как для форм

person Alasdair    schedule 22.03.2012

Как указано в комментарии, я считаю, что вы должны обрабатывать эту проверку на уровне модели. Если вам все же кажется, что лучше сделать это ближе к модели, а так как их нельзя изменить, то я бы посоветовал изменить непосредственно на уровне db:

ALTER TABLE auth_user ADD UNIQUE (email)

Это плохой способ добавить ограничение unique=True к модели User без авторизации с исправлением обезьяны.

В соответствии с просьбой, я думаю, что хороший способ настройки различных форм должен быть выполнен путем наследования от базовой формы модели. Хороший пример этого можно найти в django-registration. . Единственное отличие состоит в том, что вместо родительской формы, наследуемой от forms.Form, вы должны сделать ее модельной формой:

class MyBaseModelForm(ModelForm):
    class Meta:
        model = MyModel

Затем вы можете наследовать его и создавать различные формы из этой базовой модели:

class OtherFormWithCustomClean(MyBaseModelForm):
    def clean_email(self):
       email = self.cleaned_data['email']
       if ExtendedUser.objects.filter(email=email).exists():
          raise ValidationError('This email address already exists.')
    return email
person vascop    schedule 22.03.2012