Идиоматический способ передачи ошибок проверки модели Django в форму - PullRequest
7 голосов
/ 12 октября 2011

Пожалуйста, помогите мне понять, являются ли следующие варианты, которые я сделал, идиоматическими / хорошими, и если нет, то как их улучшить.

1) Проверка модели по сравнению с проверкой формы
Я предпочитаюпо возможности использовать новую проверку модели поверх проверки формы, поскольку это представляется более СУХИМЫМ и фундаментальным способом создания правил для данных.Два примера для простой модели записи календаря:

  • "начало должно быть раньше конца"
  • "период должен быть меньше (конец-начало)"

Является ли это идиоматичным / хорошим, чтобы поместить их на уровне модели, чтобы их не нужно было помещать в формы?Если ModelForm - лучший ответ, то как насчет использования нескольких моделей в одной форме?
(редактировать: я не осознавал, что несколько ModelForms действительно могут использоваться вместе)

2) Перенос проверки модели в форму (не ModelForm)
(правка: Оказывается, в моей ситуации не требуется заново изобретать систему между проверкой модели и проверкой формы, и приведенные ниже решения показывают, почему)
Давайте на минутку предположим, что любая ошибка проверки моделиЯ могу быть непосредственно передан и отображен непосредственно пользователю (т. Е. Игнорировать перевод ошибок проверки модели в удобные ошибки проверки формы).

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

view_with_a_form:
...
if form.is_valid():
    instance = ...
    ...
    #save() is overridden to do full_clean with optional exclusions
    try: instance.save()
    except ValidationError e:
        nfe= e.message_dict[NON_FIELD_ERRORS]
        #this is one big question mark:
        instance._errors['__all__'] = ErrorList(nfe)
#this is the other big question mark. seems unnatural
if form.is_valid()
    return response...
... #other code in standard format
#send the user the form as 1)new 2)form errors 3)model errors
return form

Как прокомментировано в коде:
a) Это идиоматический / хороший способ перенести ошибки модели в форму?

b)Является ли это идиоматическим / хорошим способом проверки на наличие новых ошибок в форме?

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

Ответы [ 2 ]

5 голосов
/ 12 октября 2011

1) Да, проверка модели вполне допустима.Вот почему ребята из Django добавили его.Формы не всегда используются в процессе сохранения моделей, поэтому, если проверка выполняется только через формы, у вас будут проблемы.Конечно, в прошлом люди обходили это ограничение, переопределяя метод save и включая проверку таким образом.Тем не менее, новая валидация модели является более семантической и дает вам возможность подключиться к процессу валидации при фактическом использовании формы.

2) В документах достаточно ясно сказано, что валидация модели (full_clean) выполняется, когда ModelForm.is_valid называется.Однако, если вы не используете ModelForm или хотите выполнить дополнительную обработку, вам нужно вызвать full_clean вручную.Вы делаете это, но неправильный подход - это переопределить save.Помните: «Явное лучше, чем неявное».Кроме того, save вызывается во многих других местах и ​​способах, и в случае ModelForm, вы на самом деле в конечном итоге выполните full_clean в два раза больше.

Тем не менее, так как документы говорят, чтоModelForm делает full_clean автоматически, я подумал, что было бы разумно увидеть, как он обрабатывает ошибки.В методе _post_clean, начиная со строки 323 django.forms.models :

# Clean the model instance's fields.
try:
    self.instance.clean_fields(exclude=exclude)
except ValidationError, e:
    self._update_errors(e.message_dict)

# Call the model instance's clean method.
try:
    self.instance.clean()
except ValidationError, e:
    self._update_errors({NON_FIELD_ERRORS: e.messages})

В свою очередь, код для _update_errors начинается со строки 248 того же модуля:

def _update_errors(self, message_dict):
    for k, v in message_dict.items():
        if k != NON_FIELD_ERRORS:
            self._errors.setdefault(k, self.error_class()).extend(v)
            # Remove the data from the cleaned_data dict since it was invalid
            if k in self.cleaned_data:
                del self.cleaned_data[k]
    if NON_FIELD_ERRORS in message_dict:
        messages = message_dict[NON_FIELD_ERRORS]
        self._errors.setdefault(NON_FIELD_ERRORS, self.error_class()).extend(messages)

Вам придется немного поиграть с кодом, но это должно дать вам хорошую отправную точку для объединения ошибок проверки формы и модели.

5 голосов
/ 12 октября 2011

[Отредактировано - надеюсь, что это отвечает вашим комментариям]

Я буду краток и откровенен, но не хочу быть невежливым:)

1) Проверка модели по проверке формы

Я полагаю, что практическое правило может заключаться в том, что, пока правило действительно связано с моделью, да, лучше проводить проверку на уровне модели.

Для нескольких моделей форм , пожалуйста, проверьте этот другой вопрос SO: Django: несколько моделей в одном шаблоне с использованием форм , не забывая о прикрепленной ссылке , которая немного стар, но все еще актуален на самом сухом способе достигнуть этого. Слишком долго, чтобы обсуждать все это здесь!

2)

  • а) Нет! Вы должны получить свою форму из ModelForm, которая будет выполнять проверку модели для вас -> вам не нужно вызывать проверку модели самостоятельно
  • б) Нет! Если вы хотите проверить модель, вы не должны пытаться сохранить ее; вам следует использовать full_clean -> так что если ваша ModelForm действительна, то вы знаете, что модель тоже действительна, и вы можете сохранить.

И да, эти ответы по-прежнему применимы даже к многомодельным формам.

Итак, что вы должны сделать, это:

  • Все еще используете ModelForm
  • не беспокойтесь о проверке модели, потому что ModelForm сделает это за вас.

В общем, если вы обнаружите, что делаете сантехнику с django, это потому, что есть другой, более простой способ сделать это!

Второй указатель должен помочь вам начать работу и значительно упростить ваш код ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...