【问题标题】:Dynamic FormWizard动态表单向导
【发布时间】:2013-09-21 02:33:18
【问题描述】:

我做了一个像ifttt.com 一样工作的项目。

为此,我使用FormWizard

实际上,这仅适用于 RSSEvernote 两个服务

我可以像 FormWizard 所期望的那样设置FORMSTEMPLATES,这是我的urls.pyviews.py 的平静:

urls.py

# wizard
url(r'^service/create/$', UserServiceWizard.as_view([RssForm, EvernoteForm,
     ServicesDescriptionForm]), name='create_service'),

views.py

from th_rss.forms import RssForm
from th_evernote.forms import EvernoteForm
from django_th.forms.base import ServicesDescriptionForm

FORMS = [("rss", RssForm),
     ("evernote", EvernoteForm),
     ("services", ServicesDescriptionForm), ]

TEMPLATES = {
    '0': 'rss/wz-rss-form.html',
    '1': 'evernote/wz-evernote-form.html',
    '2': 'services_wizard/wz-description.html'}


class UserServiceWizard(SessionWizardView):
    instance = None

    def get_form_instance(self, step):

        if self.instance is None:
            self.instance = TriggerService()
        return self.instance

    def done(self, form_list, **kwargs):
        trigger = self.instance
        trigger.provider = UserService.objects.get(
            name='ServiceRss',
            user=self.request.user)
        trigger.consummer = UserService.objects.get(name='ServiceEvernote',
                            user=self.request.user)
        trigger.user = self.request.user
        trigger.status = True
        # save the trigger
        trigger.save()
            #...then create the related services from the wizard
        for form in form_list:
            if form.cleaned_data['my_form_is'] == 'rss':
            from th_rss.models import Rss
            Rss.objects.create(
                name=form.cleaned_data['name'],
                url=form.cleaned_data['url'],
                status=1,
                trigger=trigger)
            if form.cleaned_data['my_form_is'] == 'evernote':
                from th_evernote.models import Evernote
            Evernote.objects.create(
                tag=form.cleaned_data['tag'],
                notebook=form.cleaned_data['notebook'],
                status=1,
                trigger=trigger)

        return HttpResponseRedirect('/')

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

但实际上该项目只处理 2 个服务,我不想(也无法想象)为每对新服务(如 TwitterEvernoteWizard、RssTwitterWizard、FacebookTwitterWizard 等)创建一个专用的 CBV。

首先,我必须通过这些步骤来改变流程:

  • 第一页显示用户可以选择的服务
  • 第二页询问用户他想从第 1 步选择的服务中获取哪些数据
  • 第三页显示用户可以选择的服务,无需在步骤 1 中选择一个
  • 第 4 页询问用户数据(系统将抓取的)将去往何处(在第 3 步选择的服务中)
  • 第 5 个(也是最后一个)页面显示一个描述字段来命名触发器。

有一个具体的例子可以给出:

  • 第1页我选择推特
  • 第 2 页我选择从时间轴抓取数据
  • 第3页我选择Facebook
  • 第4页我选择把数据放在墙上
  • 第 5 页我放了“这是我从 twitter 到 facebook 的触发器”;)

因此,在此过程中,我需要能够动态更改表单的内容,以使用我之前选择的服务中的 FormWizard 的名称来填充它。 TEMPLATES dict 也一样。

如您所见,在向导开始时,我无法提前知道将选择哪个服务。 这就是为什么我需要动态填充 FORMSTEMPLATES

如果有人知道如何做到这一点,或者可以提出一个继续的方法,我将不胜感激。

问候

注意:我使用 Django 1.4

【问题讨论】:

    标签: python django evernote


    【解决方案1】:

    这是我完成的处理方式

    首先,urls.py

    url(r'^service/create/$','django_th.views.get_form_list', name='create_service'),
    

    然后在 views.py 中:

    我做到了:

    def get_form_list(request, form_list=None):
        if form_list is None:
            form_list = [ProviderForm, DummyForm, ConsummerForm, DummyForm, \
                         ServicesDescriptionForm]
        return UserServiceWizard.as_view(form_list=form_list)(request)
    

    这允许定义 5 个步骤:

    • 3个已知表单(ProviderForm, ConsummerForm, ServicesDescriptionForm
    • 2 个未知的(实际上是DummyForm 两次)将在下面动态处理

    提供DummyFormforms.py

    class DummyForm(forms.Form):
        pass
    

    下一步是从ProviderForm获取数据,从中获取我选择的服务,并加载这个选择的服务的for:

    在我的 views.py 中:

    class UserServiceWizard(SessionWizardView):
    
        def __init__(self, **kwargs):
            self.form_list = kwargs.pop('form_list')
            return super(UserServiceWizard, self).__init__(**kwargs)
    
        def get_form_instance(self, step):
            if self.instance is None:
                self.instance = UserService()
            return self.instance
    
        def get_context_data(self, form, **kwargs):
            data = self.get_cleaned_data_for_step(self.get_prev_step(
                                                        self.steps.current))
            if self.steps.current == '1':
                service_name = str(data['provider']).split('Service')[1]
                #services are named th_<service>
                #call of the dedicated <service>ProviderForm
                form = class_for_name('th_' + service_name.lower() + '.forms',
                      service_name + 'ProviderForm')
           elif self.steps.current == '3':
                service_name = str(data['consummer']).split('Service')[1]
                #services are named th_<service>
                #call of the dedicated <service>ConsummerForm
                form = class_for_name('th_' + service_name.lower() + '.forms',
                      service_name + 'ConsummerForm')
            context = super(UserServiceWizard, self).get_context_data(form=form,
                                      **kwargs)
        return context
    

    这里:

    • __init__get_form_list 我在 urls.py 中定义的函数加载数据
    • get_context_data 中,我需要从ProviderFormConsummerForm 的下拉列表中选择的服务中更改第1 步和第3 步中的DummyForm。由于该服务被命名为“FoobarService”,因此我将“Service”拆分为以Foobar(Consummer|Provider)Form 和下面的class_for_name() 形式调用服务:

    class_for_name

    def class_for_name(module_name, class_name):
       m = importlib.import_module(module_name)
       c = getattr(m, class_name)
       return c
    

    终于

    有了所有这些,我可以在任何步骤动态更改表单,实际上我决定在第 1 步和第 3 步执行此操作,但可以针对任何步骤进行调整;)

    【讨论】:

    • 这就是我想要的提取物,幻想!
    猜你喜欢
    • 2021-03-10
    • 2014-06-09
    • 1970-01-01
    • 1970-01-01
    • 2016-03-05
    • 1970-01-01
    • 1970-01-01
    • 2014-03-12
    • 1970-01-01
    相关资源
    最近更新 更多