Вы можете использовать Мастер форм для модельных форм в Django? - PullRequest
10 голосов
/ 14 июля 2011

У меня есть одна модель, и я создал форму из модели, используя ModelForm.Теперь я хочу распространить форму на две страницы.Например, первые три поля появятся на первой странице, затем пользователь нажмет следующую, а последние три поля появятся на второй странице.Затем он нажимает кнопку «Отправить», и данные, добавленные пользователем, добавляются в базу данных.

Я посмотрел документы для мастера форм, и похоже, что это будет работать и для модельных форм?Кто-то может это подтвердить?

И если да, кто-то может объяснить процесс создания WizardView класса.

Этот пример приведен в документации, и я не понимаю, чтовторые два параметра есть.Является ли form_list просто списком объектов формы, которые вы создали на основе ваших классов форм?А что такое **kwargs?

class ContactWizard(SessionWizardView):
    def done(self, form_list, **kwargs):
        do_something_with_the_form_data(form_list)
        return HttpResponseRedirect('/page-to-redirect-to-when-done/')

Заранее спасибо за помощь!

Ответы [ 4 ]

23 голосов
/ 08 декабря 2012

скажем, ваша модель имеет два поля

class AModel( Model ):
    fieldA = CharField()
    fieldB = CharField()

Мы хотим установить каждое поле на отдельном шаге, используя FormWizard. Итак, мы создаем два ModelForm с, каждое из которых показывает одно поле:

class Form1( ModelForm ):
    class Meta:
        model = AModel
        fields = ( 'fieldA', )

class Form2( ModelForm ):
    class Meta:
        model = AModel
        fields = ( 'fieldB', )

Мы называем наш мастер форм AWizard; запись url.py должна выглядеть примерно так:

url( r'^$', AWizard.as_view( [ Form1, Form2 ] ) ),

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

class AWizard( SessionWizardView ):
    instance = None

    def get_form_instance( self, step ):
        if self.instance is None:
            self.instance = AModel()
        return self.instance

    def done( self, form_list, **kwargs ):
        self.instance.save()

Обратите внимание, что мы переопределяем метод get_form_instance. Этот метод возвращает экземпляр модели, с которой связаны формы.

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

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

Магия происходит, когда отправляется последняя форма. На этом этапе все формы проходят повторную проверку, каждая форма вызывает get_form_instance, и в итоге они заполняют один AModel экземпляр.

Этот экземпляр затем сохраняется в done.

6 голосов
/ 15 июля 2011

Form Wizard встроен в Django 1.4, так что это хороший способ сделать это.Он должен делать то, что вы хотите, но вам может потребоваться пара настроек.

Не беспокойтесь о kwargs в done() на данный момент - они вам не понадобятся.

form_list - это список форм, которые вы хотите использовать для своих шагов - от urls.py

urlpatterns = patterns('',
    (r'^contact/$', ContactWizard.as_view([ContactForm1, ContactForm2])),
)

[ContactForm1, ContactForm2] будет передано done() как form_list.

Что вам нужно будет сделать, это разбить ваш ModelForm на отдельные формы.Самый простой способ сделать это (если вы хотите, чтобы ваша модель была в нескольких формах), это не использовать ModelForm, а просто создать свою собственную форму.Это довольно просто:

from django import forms

class ContactForm1(forms.Form):
    subject = forms.CharField(max_length=100)
    sender = forms.EmailField()

class ContactForm2(forms.Form):
    message = forms.CharField(widget=forms.Textarea)

Как только ваши формы отражают части вашей модели, просто создайте views и patterns, как описано в документах и установите do_something_with_the_form_data(form_list) вфункция, которая дополняет вашу модель на основе данных формы, а затем выполняет сохранение.

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

2 голосов
/ 15 марта 2013

Представление, предложенное @wuerg, не работает для меня, я должен был сделать это:

class AWizard( SessionWizardView ):
    def dispatch(self, request, *args, **kwargs):
        self.instance = AModel()
        return super(ApplyWizard, self).dispatch(request, *args, **kwargs)

    def get_form_instance( self, step ):
        return self.instance

    def done( self, form_list, **kwargs ):
        self.instance.save()
        return HttpResponseRedirect(reverse(thanks))
0 голосов
/ 28 декабря 2015

Мне пришлось изменить решение @wuerg и @madmen для работы в моем сценарии использования (сохранение модели после каждого шага).Большим преимуществом этого подхода является то, что он всегда использует один и тот же экземпляр AModel вместо создания нового экземпляра для каждого шага:

class AWizard(SessionWizardView):
    instance = AModel()

    def dispatch(self, request, *args, **kwargs):
        return super(AWizard, self).dispatch(request, *args, **kwargs)

    def get_form_instance(self, step):
        return self.instance

    def done(self, form_list, **kwargs):
        self.save_model()
        return render_to_response('done.html')
...