【问题标题】:How to wrap a Django Form Wizard in a View?如何在视图中包装 Django 表单向导?
【发布时间】:2013-01-13 11:41:19
【问题描述】:

这个问题与之前在这里提出和回答的问题高度相关:How wrap a FormWizard in a View?

有人可以发布他们如何成功地将 Django 表单向导包装到视图中的确切详细信息,以便可以使用 login_required 装饰器吗?互联网上有很多关于这个主题的讨论,但它们似乎都不完整,因为它们实际上并没有展示他们是如何定义表单向导类的。

当我将浏览器指向视图时,出现以下异常:

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

当我实例化我的表单向导对象时我传递了哪些参数,这样它才不会给我这个错误? 如果您有一些有效的示例代码,请发布。

这是我的 urls.py 文件中的内容:

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

这是我的 views.py 文件中的内容:

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/')

【问题讨论】:

    标签: django django-forms django-views


    【解决方案1】:

    as_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'),
    )
    

    【讨论】:

    • 我不能指望它,但是将 login_required() 调用直接放入 urls.py 文件感觉有点笨拙。我的担忧有效吗?
    • 我也不喜欢在 urls.py 中使用装饰器,但这是 Django 文档中描述的一种方式:class-based-views#decorating-class-based-views
    • 在我点击第一个表单后,您上面的示例不会在两个表单之间前进。您能否展示如何修改 MyWizard 类来执行此操作并为表单的每个步骤指定不同的模板?
    • 我刚刚修改了示例代码。它现在包含使用 SessionFormWizard 所需的所有位。这个答案不再只是回答你原来的问题,而且还展示了一般如何使用向导。
    • 我在你的 MyWizard 类中添加了一个函数 done(self, form_list, **kwargs)。在该功能中,我需要访问用户的 ID。通过 request.user.id 可以在 Wrapped_wizard_view 中获得用户 ID。如何通过表单向导传递该值,以便可以从 done() 函数内部访问它?
    【解决方案2】:

    另一种答案 - 您可以始终在 Wizardviewas described in the documentation 上使用装饰器,而不是包装您的视图

    因此,您将执行以下导入:

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

    然后在class createObjectWizard(SessionWizardView) 中添加以下内容:

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

    这样你就不必和urls.py 搞混了——这一切都在视图中得到了处理。 希望这会有所帮助

    【讨论】:

      猜你喜欢
      • 2019-02-05
      • 1970-01-01
      • 1970-01-01
      • 2012-05-17
      • 2011-09-15
      • 2021-03-12
      • 2012-08-09
      • 2016-04-09
      • 1970-01-01
      相关资源
      最近更新 更多