Asistente de forma dinámica

Hice un proyecto que funciona como ifttt.com .

Para hacerlo yo uso FormWizard .

En realidad, eso funciona bien con los únicos 2 servicios que son RSS y Evernote

Podría configurar los FORMS y TEMPLATES como se esperaba en el Asistente para formularios, aquí hay una paz de mis urls.py y views.py :

urls.py

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

vistas.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]] 

Pero como en realidad el proyecto solo maneja 2 servicios, no quiero (y no puedo imaginar) crear un CBV dedicado para cada par de nuevos servicios como TwitterEvernoteWizard, RssTwitterWizard, FacebookTwitterWizard, etc.

Primero que todo, tendré que cambiar el proceso siguiendo estos pasos:

  • La primera página muestra los servicios que el usuario puede elegir.
  • La segunda página le pregunta al usuario qué datos desea obtener del servicio elegido en el paso 1
  • La tercera página muestra los servicios que el usuario puede elegir sin el elegido un paso1
  • La cuarta página pregunta al usuario dónde irán los datos (que tomará el sistema) (en el servicio elegido en el paso 3)
  • La quinta (y última) página muestra un campo de descripción para nombrar al activador.

Con un ejemplo concreto que dará:

  • página 1 elijo Twitter
  • página 2 elijo capturar datos de la línea de tiempo
  • página 3 elijo facebook
  • página 4 elijo poner los datos en la pared
  • página 5 pongo “Aquí está mi disparador de twitter a facebook”;)

Por lo tanto, con este proceso, necesito poder cambiar dinámicamente el contenido de los FORMULARIOS para completar con el nombre del Asistente de Formas del Servicio que elegí un paso antes. Lo mismo para las PLANTILLAS dict.

Como puede ver, al principio del Asistente, no puedo saber de antemano qué servicio se seleccionará. Es por eso que necesito rellenar dinámicamente FORMS Y TEMPLATES

Si alguien sabe cómo hacerlo o simplemente puede sugerir una manera de proceder, se lo agradeceré.

Saludos

Aviso: yo uso Django 1.4

Así es como terminé de manejarlo.

primero, urls.py :

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

entonces en views.py :

Yo si :

 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) 

Esto permite definir 5 pasos con:

  • 3 Formularios conocidos ( ProviderForm , ConsummerForm , ServicesDescriptionForm
  • 2 desconocidos ( DummyForm dos veces) que se manejarán dinámicamente a continuación

el forms.py que proporciona el DummyForm :

 class DummyForm(forms.Form): pass 

el siguiente paso es obtener los datos de ProviderForm, obtener el servicio que seleccioné y cargar los datos para este servicio seleccionado:

en mi 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_ #call of the dedicated 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_ #call of the dedicated 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 

aquí :

  • __init__ carga los datos de la función get_form_list que he definido en urls.py
  • en get_context_data Necesito cambiar el DummyForm en los pasos 1 y 3 del servicio que elegí en el menú desplegable de ProviderForm y ConsummerForm . Como el servicio se llama ‘FoobarService’, dividí ‘Servicio’ para realizar la llamada de la forma del formulario de servicio Foobar(Consummer|Provider)Form con class_for_name() continuación:

class_for_name :

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

Finalmente :

Con todo esto, puedo cambiar dinámicamente la forma sobre la marcha en cualquier paso, de hecho, decido hacerlo para los pasos 1 y 3, pero eso se puede adaptar para cualquier paso;)