Альтернатива django шаблон обработки формы? - PullRequest
7 голосов
/ 19 июля 2009

Шаблон , предложенный для обработки формы в представлении, кажется мне слишком сложным и не СУХИМЫМ:

def contact(request):
    if request.method == 'POST': # If the form has been submitted...
        form = ContactForm(request.POST) # A form bound to the POST data
        if form.is_valid(): # All validation rules pass
            # Process the data in form.cleaned_data
            # ...
            return HttpResponseRedirect('/thanks/') # Redirect after POST
    else:
        form = ContactForm() # An unbound form

    return render_to_response('contact.html', {
        'form': form,
    })

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

Ответы [ 8 ]

10 голосов
/ 19 июля 2009

Конечно, вы можете избежать повторения. В большинстве случаев вам необходимо передать в качестве аргументов класс формы и имя шаблона, который нужно использовать, вызываемую для обработки очищенных данных при отправке действительной формы и пункт назначения для перенаправления после такой обработки; Кроме того, вам нужно немного дополнительного кода, чтобы вызвать класс формы только один раз, чтобы создать связанную или несвязанную форму и правильно с ней справиться. I.e.:

def process_any_form(request, 
                     form_class, template_file_name,
                     process_data_callable, redirect_destination):

    form = form_class(request.POST if request.method == 'POST' else None)

    if form.is_bound and form.is_valid():
        process_data_callable(form.cleaned_data)
        return HttpResponseRedirect(redirect_destination)

    return render_to_response(template_file_name, {'form': form})
6 голосов
/ 24 сентября 2011

Вы правы, это может быть лучше, вот лучшая альтернатива (но продолжайте читать):

def contact(request):
     form = ContactForm(request.POST or None) # A form bound to the POST data
     if form.is_valid(): # All validation rules pass
        # Process the data in form.cleaned_data
        # ...
        return HttpResponseRedirect('/thanks/') # Redirect after POST

     return render_to_response('contact.html', {
        'form': form,
     })

Этот фрагмент взят из выступления под названием Расширенное использование форм Django от DjangoCon11.

Обратите внимание, что при этом пустая форма будет обрабатываться как действительная (даже перед отправкой), если все поля являются необязательными и вы не используете защиту CSRF. Таким образом, чтобы устранить этот риск, вам лучше использовать этот:

    def contact(request):
     form = ContactForm(request.POST or None) # A form bound to the POST data
     if request.method == 'POST' and form.is_valid(): # All validation rules pass
        # Process the data in form.cleaned_data
        # ...
        return HttpResponseRedirect('/thanks/') # Redirect after POST

     return render_to_response('contact.html', {
        'form': form,
     })
2 голосов
/ 19 июля 2009

Стандартный способ обработки форм сочетает в себе две проблемы: представление формы для редактирования и обработки результатов. Вы можете разбить это на два метода, которые привели бы к некоторому дублированию в форме идентичных вызовов render_to_response (). К тому времени, когда вы проведете рефакторинг, вы можете получить что-то менее читаемое, чем приведенная выше форма с одним методом.

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

1 голос
/ 19 июля 2009

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

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

# in urls.py
urlpatterns += patterns("", 
    (u'^...$', 'django.views.generic.create_update.update', {
        'form_class': ContactForm })
)

ContactForm должен иметь метод save(), и именно в этом заключается ваша логика обработки формы.

1 голос
/ 19 июля 2009

Универсальный обработчик Алекса опередил меня, но, ПОЭТОМУ, мы склоняемся к менее универсальной версии его предложения:

def contact(request):
    post_data = request.POST if request.method == 'POST' else None
    form = ContactForm(post_data)
    if request.method == 'POST':
        # perform normal validation checking, etc

    return render_to_response('contact.html', {
        'form': form,
         })

Если post_data имеет значение None, то форма создается как неограниченная. В противном случае связанная обработка продолжается как обычно. Это позволяет избежать дублирования конструкции ContactForm, но я согласен с ответом Дейва, что дублирующая конструкция не беспокоит меня как дубликат именно потому, что параметры конструкции разные.

0 голосов
/ 19 июля 2009

Вы можете обойти модуль форм django и просто сделать это по старинке, вы получите большую гибкость без особых потерь ИМХО.

В прошлый раз, когда я смотрел на формы django, довольно давно, я не знаю, изменились ли вещи, но, например, это не позволяет вам создавать формы в стиле ajax; по крайней мере, не легко.

0 голосов
/ 19 июля 2009

Django предоставляет несколько общих видов для создания, редактирования и удаления объектов. Возможно, вы могли бы попробовать это.

0 голосов
/ 19 июля 2009

Можно написать функцию, которая обрабатывает условия для всех форм. Вы можете сделать это, передав функцию, специфичную для этой формы после «is_valid», например:

def FormHandler(request, CleaningFunction, redirecturl):
    if request.method = 'POST':
        if request.method == 'POST': # If the form has been submitted...
            form = ContactForm(request.POST) # A form bound to the POST data
            if form.is_valid(): # All validation rules pass
                CleaningFunction(form) # Process the data in form.cleaned_data
                return HttpResponseRedirect('/thanks/') # Redirect after POST
     else:
         form = ContactForm() # An unbound form
     return form

Тогда вы бы позвонили FormHandler с вашей точки зрения. Обратите внимание, что это не проверено и может иметь ошибки.

...