El Blog de Trespams

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

Django class based views (IV)

Començam a lligar les class views amb els models de dades, que això es posa cada cop més interessant.

Fins ara hem vist un ús de les class views molt genèric, és a dir, amb el que sabem podem mostrar planes webs i gestionar el treball amb formularis.

Es comú en la majoria d'aplicacions web modernes que les dades venguin d'algún lloc, d'una base de dades per exemple. Així que la gent de Django han creat tota una sèrie de mixin i vistes específices per a simplificar-ne el treball.

Mostrar un objecte

Suposem que volem mostrar les dades que tenim d'un usuari. Com sabeu el model User de Django conté les dades dels usuaris i es troba a django.contrib.auth.models.

Voldríem que en especificar-ne la clau primària a la url poder mostrar les dades de l'usuari corresponent.

És a dir, es tracta de mostrar informació que es correspon a urls d'aquest tipus

'^prefix/(?P<pk>\d+)/$'

'^prefix/(?P<slug>[-w]+)/$'

Django ens proporciona la classe DetailView per fer precisament això. És a dir, per estalviar-nos la major part de la feina de cercar l'objecte que es correspon amb la clau primària o l'slug i passar-ho a la plantilla per a la seva presentació. Per si us ho demanaveu DetailView es troba a django.views.generic.detail.

Anem a veure un poc DetailView per dintre:

Aquesta classe hereta de SingelObjectTemplateResponseMixin i de BaseDetailView. La primera a la seva vegada és fila de una vella coneguda TemplateResponseMixin i en sobrescriu el mètode get_template_names per tal d'establir un nom de plantilla per defecte, que en el cas dels models és de la forma app/nom_detail.html, és a dir, per al nostre exemple, si no posam cap nom de plantilla agafarà per defecte auth/user_detail.html.

Per la seva banda BaseDetailView és filla de SingleObjectMixin i de View i implementa el mètode get i li passa al contexte de la plantilla la variable object amb el contingut de l'objecte que es correspon a la clau primària.

Com que object pot resultar un tant confús, Django també passa el mateix contingut a una variable amb el nom de l'objecte si el model té el nom posat al verbose_name o bé farà servir el que li indiquem a l'atribut context_object_name de la Classe.

SingleObjectMixin és la classe encarregada de fer el gruix de la feina, i com no, també implementa el mètode get_context_data per a poder passar més informació a la plantilla.

Així doncs, mostrar un objecte pot ser tan senzill com això:

al urls.py afegim:

url(r'^user/(?P<pk>\d+)/$', UserView.as_view(), name='main_user'),

i no oblidem importar UserView, que crearem dins views.py i que pot ser tan simple com:

class UserView(DetailView): 
model = User

Com que User té assignat un verbose_name='User' Django passa a la plantilla tant la variable object com la variable user i per tant en condicions normals podríem fer servir tant un nom com l'altra.

En el nostre cas, i si com jo teniu dins el context processors la línia 'django.contrib.auth.context_processors.auth' us trobareu que la variable "no funciona". Això és perquè encara que se li passi, el context processor crea també una variable anomenada 'user' amb les dades de l'usuari autenticat (si existeix), i com s'assigna just abans de generar la plantilla, el contingut que prevaleix és el del context processor.

Una cosa que em va sorprendre del SignleObjectMixin és que a més del mètode get_object implementa també get_queryset. De fet get_objectcrida a get_queryset i li aplica un filtre per clau primaria (pk) o bé per slug.

Què vol dir això, doncs que tenim un nivell extra de flexibilitat a l'hora de determinar si un objecte és presentable per pantalla o no. Basta sobreescriure el mètode get_queryset i independentment que la clau primària (o l'slug) existeixi en la base de dades, podem fer que l'objecte no es mostri. Per exemple, suposem que en el nostre exemple anterior no volem mostrar l'usuari admin.

Podem fer

class UserView(DetailView):
model = User

def get_queryset(self):
query = super(UserView, self).get_queryset()
return query.exclude(username='admin')

de manera que UserView ens mostrarà la informació de qualsevol usuari llevat de l'usuari admin, en aquest cas mostrarà un error 404.

SingleObjectMixin com hem dit, pot tornar-nos un objecte a partir de la seva clau primària o bé a partir de l'slug. Normalment en farem servir un o altre. L'ordre de prioritat és primer el pk i si aquest està buid, es mirar l'slug.

Al proper post farem una ullada a les facilitats que ens donen les generic class views per a gestionar els manteniments i veurem com es pot fer un cicle CRUD.

blog comments powered by Disqus