动态FormWizard

时间:2013-09-16 20:17:24

标签: python django evernote

我创建了一个像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。

首先,我将不得不通过这些步骤改变流程:

  • 第一页显示用户可以选择的服务
  • 第2页询问用户他希望从第1步的选择服务中获取哪些数据
  • 第3页显示用户可以选择的服务,而无需选择un step1
  • 第4页询问用户数据(系统将抓取)的位置(在步骤3的选择服务中)
  • 第5页(和最后一页)显示说明字段以命名触发器。

用一个具体的例子来说明:

  • 第1页我选择Twitter
  • 第2页我选择从时间线中获取数据
  • 第3页我选择Facebook
  • 第4页我选择将数据放在墙上
  • 第5页我把“这是我从Twitter到facebook的触发器”;)

因此,在这个过程中,我需要能够动态地更改FORMS的内容,并使用我之前选择的服务中的FormWizard名称填充它。 同样适用于TEMPLATES dict。

正如您所看到的,在向导开始时,我无法预先知道将选择哪个服务。 这就是我需要动态填充FORMSTEMPLATES

的原因

如果有人知道如何做到这一点或者只是建议继续进行,我将不胜感激。

问候

注意:我使用Django 1.4

1 个答案:

答案 0 :(得分:3)

这是我完成处理的方法

首先, 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知道表格(ProviderFormConsummerFormServicesDescriptionForm
  • 2个未知的(事实上DummyForm两次)将在
  • 下动态处理

forms.py ,提供DummyForm

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函数的数据 {li> in get_context_data我需要在DummyFormProviderForm下拉菜单中选择的服务中更改第1步和第3步中的ConsummerForm。由于该服务名为“FoobarService”,因此我将“服务”拆分为调用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步执行此操作,但可以适用于任何步骤;)