El blog de Trespams

[ x ]

Faig servir les cookies de Google Analytics per al control de visites i estadístiques..
És una pardalada, però la llei diu que us he d'avisar, ja veus. Així que si visitau aquest blog donau-vos per informats o sortiu ara mateix i netejau les cookies del vostre navegador. Si continuau llegint, suposaré que ja us està bé. Si vols saber com llevar les cookies del teu navegador: aquí ho pots trobar

Formulari compost a Django

  • Get the Englist translation of this post at: Gencat

  • Obtén la traducción al castellano de este post en: Gencat

Django té un sistema de tractament de formularis molt bo. Ens permet per una banda la reutilització de codi, ja que separa el que és la definició del formulari i la seva validació de la part de presentació.

La validació de la informació és d'allò més interessant, ja que assegura que si un camp del formulari l'hem definit com a sencer, el valor de la variable que obtindrem serà un sencer, o en cas contrari hi haurà un error de validació.

Per tot això, la idea és utilitzar el formularis de Django sempre que sigui possible i reutilitzar tot el que tinguem.

El problema es presenta quan en una plana ens n'adonam que necessitam dos formularis, no hi ha cap exemple de com fer-ho a la documentació. Veurem que una vegada solucionat el problema és tant obvi i simple que efectivament no importa documentar-ho, encara que estaria bé :)

Per a aquest exemple he posat el codi al repositori d'appfusedjango

Anem per feina

La idea és ben senzilla, crearem dos formularis i els farem servir a la nostra vista. Per a facilitar-no les coses, podem posar els dos formularis dins una llista de manera que per muntar la plana sols haurem de recorre la llista de formularis que li passam.

A l'exemple he creat dos formularis LoginForm i ContactForm, que es generaran a two_forms.html

        def two_forms(request):
           if request.method == 'POST':
               contact_form = ContactForm(request.POST)
               login_form = LoginForm(request.POST)        
               if  login_form.is_valid() and contact_form.is_valid():
                   # do whatever you need as everything is valid
                   return HttpResponseRedirect('/thanks/')
           else:
               contact_form = ContactForm()
               login_form = LoginForm()
           forms = [contact_form, login_form]
           return render_to_response('two_forms.html', {'forms': forms})
     

Com podem veure el funcionament és el mateix que en el cas d'un formulari normal, sols que hem crear-ne dos (o els que vulguem) i anar cridant al mètode is_valid per fer les validacions.

Això funciona perquè cada formulari agafa del post sols les dades que coincideixen amb els camps que té definits i perquè a l'hora de muntar la plana Django mira si el formulari té errors (la validació es fa tant cridant a is_valid com accedint als errors), d'altra manera i donat que Python fa servir l'avaluació curta de l'and, no tindríem els errors del segon formulari si el primer ja no validàs. Això explica el perquè hi ha aquesta doble via de llançar la validació a Django.

I això ens duu de manera natural a la següent qüestió, què passa si als formularis hi ha camps amb al mateix nom?

Doncs que Django no serà capaç d'esbrinar a quin camp correspon cada cosa in ens trobarem amb un petit problema.

Però tranquils, això està controlat, basta afegir un prefix que sigui únic per a cada formulari. Aquest prefix s'afegirà al nom dels camps que es generen per a l'HTML i d'aquesta manera en recuperar la informació Django sabrà quin camp correspon a cada formulari.

Hem de tenir cura d'assignar el prefixe tant a la part del GET com a la part de POST de la funció.

I això és tot, fàcil i net!

Observacions finals

A l'exemple de tres formularis amb el mateix nom he deixat codi de depuració, el import ipdb; ipdb.set_trace(), ho podeu llevar, levar sols la i del ipdb o bé instal·lar el ipdb, un depurador un poc més potent que el pdb de tota la vida i amb ressaltat de sintaxis.

blog comments powered by Disqus
<<<<<<< main/templates/puput/base.html ======= >>>>>>> main/templates/puput/base.html