3

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

为此,我使用FormWizard.

实际上,这适用于仅有的 2 项RSS服务Evernote

我可以像 FormWizard 所期望的那样设置FORMSand TEMPLATES,这是我的urls.pyand的平静views.py

网址.py

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

视图.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 步选择的服务中获取哪些数据
  • 第三页显示用户可以选择的服务,而无需选择 un step1
  • 第 4 页向用户询问数据(系统将抓取的)将去往何处(在步骤 3 选择的服务中)
  • 第 5 页(也是最后一页)显示一个描述字段来命名触发器。

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

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

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

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

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

问候

注意:我使用 Django 1.4

4

1 回答 1

5

这是我完成处理的方法

首先,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实际上是两次)将在下面动态处理

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
  • get_context_data我需要DummyForm从我在下拉菜单中选择的服务中更改第 1 步和第 3 步中的ProviderFormConsummerFormFoobar(Consummer|Provider)Form由于该服务被命名为“FoobarService”,我将“Service”拆分为以下形式的服务调用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 步中执行此操作,但这可以适用于任何步骤;)

于 2013-09-25T07:49:08.810 回答