El Blog de Trespams

Blog personal sobre tecnologia, gestió de projectes i coses que se me passen pel cap

Django class based views (III)

En aquest apunt veurem com fer servir les generic class views per a fer feina amb formularis.

Seguirem la documentació de Django que tracta dels formularis. Allà ens fa referència a un formulari de contacte creat com:

from django import forms


class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
message = forms.CharField()
sender = forms.EmailField()
cc_myself = forms.BooleanField(required=False)

i la vista associada

def contact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
return HttpResponseRedirect('/thanks/')
else:
form = ContactForm()
return render_to_response('contact.html', {'form': form, })

El que farem ara és fer el mateix però fent servir les generic class views.

El primer que hem de veure és què hem de fer servir. Necessitam gestionar un formulari, la seva validació i tornar la redirecció cap a una nova plana web en cas que tot vagi bé.

Si feim una ullada a la jerarquia de classes del mòdul edit podem veure que la classes que compleix tot el que volem es diu FormView.

FormView està composada pel mixin TemplateResponseMixin que ja coneixem i BaseFormView que a la seva vegada està format per dos mixins més FormMixin i ProcessFormView.

FormMixin ens proporciona els mètodes per a gestionar el form i ProcessFormView que descendeix de View ens proporciona les respostes a les cridades get, post i put.

L'equivalent fent servir les generic class views ens queda:

class ContactView(FormView):
form_class = ContactForm
success_url = reverse_lazy('main_thanks')
template_name = 'main/index.html'

def form_valid(self, form):
print form.cleaned_data
return super(ContactView, self).form_valid(form)

és a dir, hem de dir li a la classe quin formulari farem servir, això ho feim a form_class o bé amb la rescriptura del mètode get_form_class que ens ha proporcionat el mixin FormMixin o fin i tot instanciant el formulari directament si fem la rescriptura de get_form

Els mètodes form_valid i form_invalid ens permeten definir què em de fer amb el formulari. Normalment ens bastarà sobreescriure el mètode form_valid per a adaptar-lo a les nostres necessitats.

I qui crida al mètode is_valid del formulari? Doncs el post que prové de ProcessFormView. Recordem que un mixin té accés a tot l'objecte que el fa servir, i per tant també té accés als mètodes el mixin FormMixin.

Suposem ara que volem que el nostre formulari agafi uns certs valors inicials, això ho podem fer amb l'atribut initial definit a FormMixin o bé a partir de la reescriptura del mètode get_initial, segons la nostra aplicació ens convindrà un mètode o un altre.

class ContactView(FormView):
form_class = ContactForm
success_url = reverse_lazy('main_thanks')
template_name = 'main/index.html'
initial = {'subject': u'This is a test form'}

def form_valid(self, form):
print form.cleaned_data
return super(ContactView, self).form_valid(form)

Si a més hem de passar dades addicionals a la plantilla Django, FormMixin ens proporciona un altre vell conegut, el mètode get_context_data que fa el mateix que feia al TemplateView. Això sí, ara hem de tenir cura de cridar al mètode pare, ja que als kwargs hi ha la definició del formulari. Per a evitar-nos conèixer què fa i que no fa, millor cridar al mètode pare i a partir d'aquí afegir-hi les variables que necessitem:

class ContactView(FormView):
form_class = ContactForm
success_url = reverse_lazy('main_thanks')
template_name = 'main/index.html'
initial = {'subject': u'This is a test form'}

def form_valid(self, form):
print form.cleaned_data
return super(ContactView, self).form_valid(form)

def get_context_data(self, **kwargs):
context = super(ContactView, self).get_context_data(**kwargs)
context['msg'] = u'Hello World'
return context

I no hem de perdre de vista que estam fent feina amb classes. Podem anar afegint els mètodes que necessitem a la classe, de manera que cada funció ens quedi manejable.

I ja per acabar un petit avís, he fet servir reverse_lazy per a obtenir el valor de la url, però aquesta funció no hi és a Django 1.3. Per utilitzar el nom de la url enlloc de la url en sí, en Django 1.3 o bé hem de sobreescriure get_success_url o bé utilitzar l'snippet que apareix a Django Snippets i que resol això d'una manera molt elegant:

from django.utils.functional import lazy
from django.core.urlresolvers import reverse

reverse_lazy = lambda name=None, *args: lazy(reverse, str)(name, args=args)

Això encara dóna per més, fins al proper article!

blog comments powered by Disqus