Как сделать многоступенчатую форму в Django?

Я хотел бы создать в Django форму mutli-step, которая только отправляет данные для обработки в конце всех шагов. Каждый шаг должен иметь возможность доступа и отображения данных, которые мы вводили на предыдущих этапах.

Есть ли способ сделать это с помощью Django? Django Form-Wizard не может справиться с этой базовой функциональностью.

Ответ 1

Конечно, есть способ сделать это в Django.

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

При поиске вы можете найти приложение, которое кто-то уже написал, который будет делать то, что вы хотите, но делать то, что вам нужно, не сложно с Django или с любой другой инфраструктурой.

Пример, игнорируя инструкции импорта:

#models/forms

class Person(models.Model):
    fn = models.CharField(max_length=40)

class Pet(models.Model):
    owner = models.ForeignKey(Person)
    name = models.CharField(max_length=40)

class PersonForm(forms.ModelForm):
    class Meta:
        model = Person

class PetForm(forms.ModelForm):
    class Meta:
        model = Pet
        exclude = ('owner',)

#views
def step1(request):
    initial={'fn': request.session.get('fn', None)}
    form = PersonForm(request.POST or None, initial=initial)
    if request.method == 'POST':
        if form.is_valid():
            request.session['fn'] = form.cleaned_data['fn']
            return HttpResponseRedirect(reverse('step2'))
    return render(request, 'step1.html', {'form': form})

def step2(request):
    form = PetForm(request.POST or None)
    if request.method == 'POST':
        if form.is_valid():
            pet = form.save(commit=False)
            person = Person.objects.create(fn=request.session['fn'])
            pet.owner = person
            pet.save()
            return HttpResponseRedirect(reverse('finished'))
    return render(request, 'step2.html', {'form': form})

Мы предположим, что step2.html имеет ссылку, чтобы вернуться к step1.html.

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

Ни один из этих кодов не был протестирован, но он должен вас поймать.

Ответ 2

Вы можете легко сделать это с помощью мастера форм django-formtools. Простым примером может быть следующее.

forms.py

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.py

from django.shortcuts import redirect
from formtools.wizard.views import SessionWizardView

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

urls.py

from django.conf.urls import url

from forms import ContactForm1, ContactForm2
from views import ContactWizard

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