How to wrap a Django Form Wizard in a View?

拜拜、爱过 提交于 2019-11-30 17:39:14

问题


This question is highly related to one that was previously asked and answered here: How wrap a FormWizard in a View?

Can someone post exact details of how they have successfully wrapped a Django Form Wizard into a view so that the login_required decorator can be used? There are numerous discussions of this topic on the internet but they all seem to be incomplete because they don't actually show how they have defined their Form Wizard class.

When I run point my browser to the view, I get the following exception:

__init__() takes exactly 1 non-keyword argument (2 given) in views.py line #108

What arguments do I pass when I instantiate my Form Wizard object such that it doesn't give me this error? If you have some sample code that works, please post it.

Here is whats in my urls.py file:

url(r'^createObject/$', views.createObjectView, name='createObject'),

Here is whats in my views.py file:

CREATE_OBJECT_FORMS = [
    ("createMyForm0", createObjectForm0),
    ("createMyForm1", createObjectForm1),
    ("createMyForm2", createObjectForm2),
    ("createMyForm3", createObjectForm3),
]

CREATE_OBJECT_TEMPLATES = {
    "createMyForm0": "myApp/form0.html",
    "createMyForm1": "myApp/form1.html",
    "createMyForm2": "myApp/form2.html",
    "createMyForm3": "myApp/form3.html",
}




@login_required
def createObjectView(request):
    # Set up the dictionary of initial data for the form
    # In this case, we are pre-filling some data from the first form only
    initial = {0: {}}

    # Create the form wizard
    form = createObjectWizard(
        [
            createObjectForm0,
            createObjectForm1,
            createObjectForm2,
            createObjectForm3,
        ], 
        initial=initial      # This is Line #108
    )

    # Call the form wizard passing through the context and the request
    return form(context=RequestContext(request), request=request)    




class createObjectWizard(SessionWizardView):
    def get_template_names(self):
        return [CREATE_OBJECT_TEMPLATES[self.steps.current]]

    def done(self, form_list, **kwargs):
        doSomethingFunction(form_list)
        return HttpResponseRedirect('/objectCreated/')

回答1:


The as_view function converts a class based view into a callable view:

myapp/views.py

from django import forms
from django.contrib.auth.decorators import login_required
from django.contrib.formtools.wizard.views import SessionWizardView
from django.template.response import TemplateResponse

class Form1(forms.Form):
    a = forms.CharField()

class Form2(forms.Form):
    b = forms.CharField()

FORMS = [("step1", Form1),
         ("step2", Form2)]

TEMPLATES = {"step1": "wizard_step.html",
             "step2": "wizard_step.html"}

class MyWizard(SessionWizardView):

    def get_template_names(self):
        return [TEMPLATES[self.steps.current]]

    def done(self, form_list):
        # get data from forms
        a = self.get_cleaned_data_for_step('step1')['a']
        b = self.get_cleaned_data_for_step('step2')['b']
        # access the request as self.request
        request = self.request
        # (...)
        # return response
        return TemplateResponse(request, 'wizard_success.html', {
            'a': a,
            'b': a
        })

wizard_view = MyWizard.as_view(FORMS)

@require_login
def wrapped_wizard_view(request):
    return wizard_view(request)

myapp/templates/wizard_step.html

{% extends "base.html" %}
{% load i18n %}

{% block content %}

<form method="post">
{% include "formtools/wizard/wizard_form.html" %}
</form>

{% endblock %}

myapp/urls.py

from django.conf.urls import patterns, url

urlpatterns = patterns('myapp.views',
    url(r'^wizard/$', 'wrapped_wizard_view'),
)



回答2:


An alternative answer - instead of wrapping your view you could always use a decorator on your Wizardview class, as described in the documentation

You would therefore do the following imports:

from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator

and then within class createObjectWizard(SessionWizardView) you would add the following:

 @method_decorator(login_required)
 def dispatch(self, *args, **kwargs):
     return super(createObjectWizard, self).dispatch(*args, **kwargs)

this way you don't have to mess with urls.py - it's all taken care of within the view. Hope this helps



来源:https://stackoverflow.com/questions/14590759/how-to-wrap-a-django-form-wizard-in-a-view

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!