Dynamic FormWizard

I made a project that works like ifttt.com .

For this I use FormWizard .

Actually, this only works great with two RSS and Evernote services.

I could set FORMS and TEMPLATES as expected in FormWizard, here is the world of my urls.py and views.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]] 

But since in fact the project processes only 2 services, I do not want (and cannot imagine) creating one dedicated CBV for each pair of new services, such as TwitterEvernoteWizard, RssTwitterWizard, FacebookTwitterWizard, etc.

So, first of all, I will need to change the process to these steps:

  • The first page displays the services that the user can select.
  • The second page asks the user what data he wants to capture from the selected service in step 1.
  • The third page displays the services that the user can choose without selecting un step1
  • The 4th page asks the user where the data will be displayed (which the system will capture) (in the selected service in step 3)
  • The fifth (and last) page displays a description field for the trigger name.

With a specific that will give:

  • page 1 I choose Twitter
  • page 2 I choose to capture data from the timeline
  • page 3 I choose Facebook
  • page 4 I choose to place data on the wall
  • page 5 I put "Here is my twitter trigger on facebook";)

So, with this process, I need to be able to dynamically change the contents of FORMS to populate it with the name FormWizard from the Service, which I chose one step earlier. Same for TEMPLATES dict.

As you can see, at the beginning of the Wizard I cannot know in advance which service will be selected. This is why I need to dynamically populate FORMS and TEMPLATES

If someone knows how to do this or can simply suggest a way to continue, I will appreciate it.

considers

notice: I am using Django 1.4

+1
source share
1 answer

this is how i finished processing it

first urls.py :

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

then in views.py :

I did:

 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) 

this allows you to define 5 steps with:

  • 3 famous forms ( ProviderForm , ConsummerForm , ServicesDescriptionForm
  • 2 unknowns ( DummyForm two times actually) that will be processed dynamically below

forms.py that DummyForm provides:

 class DummyForm(forms.Form): pass 

the next step is to get data from ProviderForm, get the service I selected and load the value for this selected service:

in my 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 

here:

  • __init__ loads data from the get_form_list function defined in urls.py
  • in get_context_data I need to change the DummyForm in steps 1 and 3 of the service I selected from the ProviderForm and ConsummerForm drop-down list. Since the service is called "FoobarService", I split the "Service" to make a call to the Foobar(Consummer|Provider)Form service form with class_for_name() below:

class_for_name :

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

Finally :

with all this, I can dynamically change the shape "on the fly" at any stage, in fact, I decide to do this for steps 1 and 3, but it can be adapted for any step;)

+3
source

Source: https://habr.com/ru/post/954845/


All Articles