Inici de sessió d'usuari


Capítol 9: Vistes genèriques


Aquí tornem a recórrer al tema d'aquest llibre: el pitjor és, el desenvolupament web és avorrit i monòton.

Fins ara hem tractat com Django intenta eliminar alguna d'aquesta monotonia amb les capes de model i les plantilles, però els desenvolupadors web també experimenten aquesta avorriment a nivell de les vistes.

Les vistes genèriques de Django s'han desenvolupat per facilitar aquest cas. Aquestes prenen certs patrons i idiomes comuns en el desenvolupament de vistes i les abstrauen per que puguis escriure ràpidament vistes comuns sobre les dades sense haver d'escriure massa codi.

En efecte, quasi cada exemple de vista en els capítols anteriors podria ser re-escrit amb l'ajuda de les vistes genèriques.

Django conté vistes genèriques per fer el següent:

  • Processar tasques "simples" comunes: re-dirigir a diferents pàgines, i imprimir una plantilla indicada.
  • Mostrar una pàgina de llista o de detall per un objecte únic. Per exemple, l'índex de documentació Django (http://www.djangoproject.com/documentation/) i les pàgines de documents individuals estan construïdes així. La llista i l'índex de crims per les vists del Capítol 5 podrien fàcilment ser re-escrites usant vistes genèriques; ho farem després.
  • Presentar objectes basats en dates en pàgines d'arxiu any/mes/dia, detalls associats i "últimes" pàgines. Els arxius d'any, mes i dia del weblog de Django (http://www.djangoproject.com/weblog/) estan fes amb aquestes, xom l'arxiu de notícies de ljworld.com i un munt més.
  • Permetre als usuaris crear, modificar i eliminar objectes -- amb o sense autorització.

Ajuntar, aquestes vistes proporcionar interfícies senzilles per processar les tasques més comunes que puguin trobar els desenvolupadors.

Utilitzant vistes genèriques

Totes aquestes vistes s'utilitzen per crear diccionaris en els teus fitxers URLconf i passant aquests diccionaris com a tercer membre de la tupla URLconf d'un patró determinat.

Per exemple, aquí hi ha la URLconf per una aplicació de weblog simple que funciona com a bloc a djangoproject.com:

from django.conf.urls.defaults import *
from django_website.apps.blog.models import Entry

info_dict = {
    'queryset': Entry.objects.all(),
    'date_field': 'pub_date',
}

urlpatterns = patterns('django.views.generic.date_based',
   (r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\w{1,2})/(?P<slug>[-\w]+)/$', 'object_detail', dict(info_dict, slug_field='slug')),
   (r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\w{1,2})/$',                  'archive_day',   info_dict),
   (r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$',                                   'archive_month', info_dict),
   (r'^(?P<year>\d{4})/$',                                                       'archive_year',  info_dict),
   (r'^/?$',                                                                     'archive_index', info_dict),
)

Com pots veure, aquest URLconf defineix unes quantes opcions a info_dict. 'queryset' dona a la vista genèrica un QuerySet d'objectes a utilitzar (en aquest cas, tots els objectes Entry) i li diu a la vista genèrica quin model s'utilitza. Els arguments que faltes de cada vista genèrica es prenen de les captures amb nom del URLconf.

Aquesta és realment tot el codi "vista" del weblog de Django! L'única cosa que falta és escriure una plantilla.

La documentació de cada vista genèrica es fa a continuació, juntament amb una llista de tots els arguments que esperen les vistes genèriques. Recorda que com en l'exemple anterior, els arguments poden venir dels patrons URL (com month, day, year,, etc, fa) o des d'un diccionari d'informació addicional (com amb queryset,date_field, etc.).

Moltes vistes genèriques requereixen la clau queryset, que és una instància QuerySet; mireu la API de referència de base de dades en l'Apèndix 3 per tenir més informació sobre els objectes QuerySet.

Moltes vistes també utilitzen diccionaris extra_context opcionals que pots utilitzar per passar qualsevol informació auxiliar que vulguis veure. Els valors en el diccionari extra_context pot tenir funcions o altres objectes. Les funcions són avaluades abans que passin a la plantilla.

Vistes genèriques "Simples"

El mòdul django.views.generic.simple conté vistes simples per dedicar a un munt de casos comuns: imprimir una plantilla quan no cal lògica de vista, i publicar una re-direcció.

Imprimir una plantilla

La funció django.views.generic.simple.direct_to_template imprimeix una plantilla, passada a la variable de la plantilla {{ params }}, que és un diccionari dels paràmetres capturats en la URL.

Exemple

Donats els següents patrons URL:

urlpatterns = patterns('django.views.generic.simple',
    (r'^foo/$',             'direct_to_template', {'template': 'foo_index.html'}),
    (r'^foo/(?P<id>\d+)/$', 'direct_to_template', {'template': 'foo_detail.html'}),
)

una petició a /foo/ hauria d'imprimir la plantilla foo_index.html, i una petició a /foo/15/ hauria d'imprimir el foo_detail.html amb una variable de context {{ params.id }} que serà posat a 15.

Arguments requerits

Plantilla
El nom complet de la plantilla a utilitzar

Redireccionar a una altra URL

django.views.generic.simple.redirect_to re-dirigeix a una altra URL. La URL indicada pot contenir una cadena formatada amb estic de diccionari. Que serà interpolada amb els paràmetres capturats per la URL.

Si la URL és None, Django retornarà un missatge HTTP 410 (Gone).

Exemple

Aquesta exemple re-direcciona de /foo// a /bar//:

urlpatterns = patterns('django.views.generic.simple',
    ('^foo/(?p<id>\d+)/$', 'redirect_to', {'url': '/bar/%(id)s/'}),
)

Aquest exemple retornar un error HTTP 410 per peticions a /bar/:

urlpatterns = patterns('django.views.generic.simple',
    ('^bar/$', 'redirect_to', {'url': None}),
)

Arguments requerits

url
La URL on es re-dirigeix, com a cadena de caràcters. O None per retornar una resposta HTTP 410 ("gone").

Vistes genèriques més complexes

Encara que les vistes genèriques simples són certament útils, el poder real de les vistes genèriques Django ve amb les vistes més complexes que et permeten construir pàgines CRUD (crear/retornar/modificar/esborrar) comunes amb el mínim de codi.

Aquestes vistes es divideixen en un quants tipus:

  • Vistes de llistes/detall, que proporcionen llistes planes d'objectes i pàgines en detall d'objectes individuals (per exemple, pàgines amb un llistat de llocs i la pàgina amb la informació d'un lloc en concret).
  • Vistes basades en dades, que proporcionen pàgines amb informació relacionada amb la data any/mes/dia.
  • Vistes per crear/modificar/esborrar, que et permeten crear vistes per crear, modificar o esborrar objectes.

Arguments comuns opcionals

Moltes d'aquestes vistes prenen un gran nombre d'arguments opcionals que poden controlar varies característiques. Molts d'aquests arguments poden donar-se a qualsevol de les vistes, així moltes de les vistes següents podran utilitzar aquesta llista d'arguments opcionals:

allow_empty
Un valor booleà que especifica si cal mostrar la pàgina si no hi ha objectes. Si aquest és False i no hi ha objectes, la vista enviarà un pàgina d'error 404. Per defecte, això és False

context_processors
Una llista de processadors del context de plantilla per aplicar a la plantilla de la vista. Mira el Capítol 10 per tenir més informació sobre les processadors de context de plantilla.

extra_content
Un diccionari de valors a afegir al context de la plantilla. Per defecte, aquest és un diccionari buit. Si un valor del diccionari és pot cridar, la vista genèrica el cridarà abans d'imprimir la plantilla.

mimetype
El tipus MIME a usar en el resultat del document. Per defecte el valor es posa a DEFAULT_MIME_TYPE.

template_loader
El carregador de plantilles a utilitzar quan es carrega la plantilla. Per defecte, és el django.template.loader. Mira el Capítol 10 per tenir més informació sobre els carregadors de platilles.

template_name
El nom complet de la plantilla a utilitzar en l'impressió de la pàgina. Això et permet sobre-escriure el nom de la plantilla per defecte derivada de la QuerySet

template_object_name
Designa el nom de la variables de plantilla a usar en el context de la plantilla. Per defecte, val 'object'. Les vistes llista que llisten més d'un objecte se li adjuntarà un '_list' al valor d'aquest paràmetre.

Vistes genèriques de llista/detall

Les vistes genèriques de vista-detall (en el mòdul django.views.generic.list_detail) abarquen els casos comuns on es mostren un llistat d'element en una vista, i les vistes individuals "en detall" d'aquests elements en una altra.

Pels exemples de la resta d'aquest càpito, treballarem amb els objectes simples llibre/autor/editorial dels capítols 5 i 6:

class Publisher(models.Model):
    name = models.CharField(maxlength=30)
    address = models.CharField(maxlength=50)
    city = models.CharField(maxlength=60)
    state_province = models.CharField(maxlength=30)
    country = models.CharField(maxlength=50)
    website = models.URLField()

class Author(models.Model):
    salutation = models.CharField(maxlength=10)
    first_name = models.CharField(maxlength=30)
    last_name = models.CharField(maxlength=40)
    email = models.EmailField()
    headshot = models.ImageField()

class Book(models.ModelField):
    title = models.CharField(maxlength=100)
    authors = models.ManyToManyField(Author)
    publisher = models.ForeignKey(Publisher)
    publication_date = models.DateField()

També treballarem amb el mòdul URL; si has seguit fins aquí, pots començar amb un esquelet de la configuració URL a bookstore.urls:

from django.conf.urls.defaults import *
from django.views.generic import list_detail, date_based, create_update
from bookstore.models import Publisher, Author, Book

urlpatterns = patterns('',
    # We'll add URL patterns here.
)

La construirem amb vistes genèriques.

Llistats d'objectes

La vista django.views.generic.list_detail.object_list s'utilitza per crear una pàgina que representi una llista d'objectes.

Exemple

Podem utilitzar la vista object_list per mostrar una llista simple de tots els autors d'una llibreria. Primer, necessitem construir un diccionari "info" per la vista genèrica. Afegeix el següent codi al principi del fitxer bookstore/urls.py:

author_list_info = {
    'queryset' :   Author.objects.all(),
    'allow_empty': True,
}

Després, necessitarem registrar aquesta vista en una URL en particular. Poder fer-ho afegit aquesta línia (dins de la directirva patterns):

(r'authors/$', list_detail.object_list, author_list_info)

Des d'aquí, només cal que creem una plantilla per a imprimir aquesta vista genèrica. Com que no hem proporcionat el paràmetre template_name (mireu després), Django decidirà el nom de la plantilla; aquí usarà el bookstori/author_list.html. Mireu més avall més detalls de com és realitza aquesta decisió.

Arguments requerits

queryset
Un QuerySet d'objectes a llistar.

Arguments opcionals

paginate_by
Un enter indicant quants objectes han de mostrar-se per pàgina. Si s'indica, la vista paginarà els objectes amb paginate_by objectes en cada pàgina. La vista esperarà un paràmetre page (via GET) contenint el número de pàgina començant per zero, o una variable page especificada en la URLconf. Mira més avall les "Notes sobre paginació".

A més, aquesta vista utilitza un d'aquests arguments comuns descrits més anteriorment:

  • allow_empty
  • context_processors
  • extra_content
  • mimetype
  • template_loader
  • template_name
  • template_object_name

Nom de la plantilla

Si no s'especifica el nom de la plantilla, aquesta vista usarà la plantilla <app_label>/<model_name>_list.html per defecte. Ambdues etiquetes són extretes del paràmetre queryset: l'etiqueta de l'aplicació és el nom de l'aplicació que el model té definit, i el nom del model és la versió en minúscules del nom de la classe model.

Així, si passe Author.objectes.all() com a queryset, l'etiqueta de l'aplicació hauria de ser bookstore i el nom del model seria author. Això significa que la plantilla per defecte hauria de ser bookstore/author_list.html.

Context de plantilla

A banda de l'extra_context, el context de la plantilla conté:

object_list
El llistat d'objectes. Aquest nom de variable depèn el paràmetre template_object_name, que és 'object' per defecte. Si template_object_name és 'foo' aquest nom de variable serà foo_list

is_paginated
Un valor booleà que representa si els resultats estan paginats. Especialment, val False si el nombre de objectes disponibles és menor o igual a paginate_by

Si els resultats són paginats, el context contindrà aquestes variables extres:

results_per_page
El nombre d'objectes per pàgina. (El mateix que el paràmetre paginate_by).

has_next
Un booleà que indica si hi ha pàgina següent.

has_previous
Un booleà que indica si hi ha pàgina anterior.

page
El número de pàgina actual, com a enter. Aquest comença per 1.

next
El número de la pròxima pàgina. Si no n'hi ha, representarà el teòric número si aquesta existís. Aquest comença per 1.

previous
El número de la pàgina anterior. Aquest comença per 1.

pages
El nombre total de pàgines, en un enter.

hits
El nombre total d'objectes en tots les pàgines, no només en aquesta.

Una nota sobre la paginació:
Si s'especifica paginate_by, Django paginarà els resultats. Pots especificar el número de pàgina en la URL de dues formes:

  • Utilitzant el paràmetre page en el URLconf. Per exemple, això és el que el teu URLconf hauria de tenir:
    (r'^objects/page(?P<page>[0-9]+)/$', 'object_list', dict(info_dict))
    
  • Passar el número de pàgina via un paràmetre page de cadena de caràcters. Per exemple, una URL podria quedar així:
    /objects/?page=3
  • En ambdós casos, page començaria per 1, no per 0, així la primera pàgina s'hauria de representar per 1.

Vistes de detall

La vista django.views.list_detail.object_detail conté una vista "detall" per un objecte únic.

Exemple

Ampliant l'exemple anterior, podríem fer una vista detall per a un autor. Enviant un diccionari d'informació com aquest:

author_detail_info = {
    "queryset" : Author.objects.all(),
    "template_object_name" : "author",
}

Podríem usar un patró URL com aquest:

(r'^authors/(?P<object_id>\d+)/$', list_detail.object_detail, author_detail_info),

Per mostrar els detalls d'un llibre en contret, imprimirem la plantilla bookstore/author_detail.html. En aquesta plantilla, el propi objecte Author es posarà dins de la variable {{ author }}.

Arguments requerits

queryset
Un QuerySet on es cercarà l'objecte.

Algun d'aquests dos:
object_id
El valor de la clau primària de l'objecte.

slug
l'etiqueta d'un objecte donat. Si passe aquest camp, llavors l'argument slug_field (mira'l a continuació) també hi haurà de ser.

Arguments opcionals

slug_field
El nom del camp de l'objecte que té l'etiqueta. Aquest és requerit si utilitzes l'argument slug, però no cal si estàs usant l'argument object_id

template_name_field
El nom del camp de l'objecte el valor del qual és el nom de la plantilla a utilitzar. Això et permet guardar noms de plantilles en les teves dades.

En altres paraules, si el teu objecte té un camp 'the_template' que conté una cadena 'foo.html', i template_name_field val 'the_template', llavors la vista genèrica d'aquest objecte utilitzarà la plantilla 'foo.html'.

És una mica rebuscat, però és útil en alguns casos.

Aquesta vista també utilitza un d'aquests arguments comuns descrits més anteriorment:

  • context_processors
  • extra_content
  • mimetype
  • template_loader
  • template_name
  • template_object_name

Nom de la plantilla

Si no s'especifiquen en template_name i template_name_field, aquesta vista usarà la plantilla per defecte /_detail.html.

El context de la plantilla

A banda del extra_context, el context de la plantilla tindrà:

object
L'objecte. Aquest nom de variables depèn del paràmetre template_object_name, que és 'object' per defecte. Si template_object_name és 'foo', el nom de la variable serà foo

Vistes genèriques basades en dates

Les vistes genèriques basades en dates, s'utilitzen generalment per proporcionar un conjunt de pàgines "arxiu" per material datificat. Pensa en arxius any/mes/dia d'un diari, o un blog com l'oficial de Django descrit a l'inici d'aquest capítol.

En aquesta exemple, utilitzarem l'objecte Book anterior, i construirem una forma de navegar pels llibres publicats per any, mes i dia. Fixa't que per cadascuna d'aquestes vistes, hem de dir-li a Django el nom del camp data que volem que utilitzi d'índex. Hem de proporcionar-li aquesta informació ja que els models podrien contenir múltiples camps de data i hora.

En el futur...
Per defecte, aquestes vistes ignoren els objectes amb dates futures.

Això vol dir que si intentes visitar una pàgina d'arxiu del futur, Django automàticament et mostrarà un error 404, encara que hi hagi objectes publicats en aquella data.

Així, pots publicar objectes en el futur que no apareguin fins després de la seva data de publicació.

Tanmateix, per alguns tipus d'objectes basats en dates, això no és massa apropiat (per exemple, un calendari d'esdeveniments). Per aquestes vistes, activar l'opció allow_future a True farà que els objectes futurs hi apareguin (i permetrà als usuaris visitar pàgines d'arxiu "futures").

índex de l'arxiu

La vista django.views.generic.date_based.archive_index proporciona una pàgina d'index d'alt nivell per mostrar els "últims" objectes, per data.

Exemple

Un publicador típic probablement vol destacar els llibres publicats recentment. Podem usar la vista archive_index per aquesta tasca comuna. Aquí hi ha un diccionari d'informació:

book_info = {
    "queryset"   : Book.objects.all(),
    "date_field" : "publication_date"
}

I la corresponent urlconf (que arrela aquest índex al nivell més baix des qualsevol inclòs):

(r'^books/$', date_based.archive_index, book_info),

Arguments requerits

date_field
El nom del DateField o DateTimeField del model QuerySet que haurà d'usar-se en l'arxiu basat en dates per determinar els objectes de la pàgina.

queryset
Un QuerySet d'objectes que servirà l'arxiu.

Arguments opcionals

allow_future
Un booleà que especifica si s'han d'incloure els objectes "futurs" en aquesta pàgina, s'ha descrit en la nota anterior.

num_latest
El número dels últims objectes a enviar al context de la plantilla. Per defecte, són 15.

Aquesta vista també utilitza un d'aquests arguments comuns descrits més anteriorment:

  • allow_empty
  • context_processors
  • extra_content
  • mimetype
  • template_loader
  • template_name

Nom de la plantilla

Si no s'expecifica template_name, aquesta vista usarà la plantilla per defecte /_archive.html.

Context de la plantilla

A més de l'extra_context, aquest context de plantilla també tindrà:

date_list
Una llista d'objectes datetime.date representant tots els anys que hi ha objectes disponibles dins del queryset. Aquests estaran ordenats al revés.

Per exemple, si tens un blog amb entrades del 2003 al 2007, aquest contindrà quatre objectes datetime.date: un per cadascun d'aquests anys.

Arxius d'Any

La vista django.views.generic.date_based.archive_year proporciona una pàgina d'arxiu anual mostrant tots els mesos disponibles en l'any indicat.

Exemple

Continuant amb el nostre exemple, volem afegir una forma de veure tots els llibres publicats en un any. Podem seguir usant el diccionari book_info de l'exemple anterior, però aquesta vegada cridarem a la vista archive_year:

(r'^books/(?P<year>\d{4})/?$', date_based.archive_year, book_info),

Com que probablement hi haurà molts llibres publicats cada any, només mostrarem una llista dels anys en que hi ha disponibles llibres. Per conveniència, això és el que Django fa per defecte; per canviar-ho podríem usar l'argument make_object_list; mira-ho més avall.

Arguments requerits

date_field
Com el d'abans.

queryset
Un QuerySet d'objectes que servirà l'arxiu.

year
L'any de 4 dígits que serveix l'arxiu (normalment utilitzat en els paràmetres de la URL),

Arguments opcionals

make_object_list
Un booleà que especifica si s'ha de retornar la llista completa d'objecte de l'any i passar-los a la plantilla. Si és True, aquest llistat d'objectes serà disponible per la plantilla com a object_list. (El nom object_list pot ser diferent; mira la informació sobre object_list en la secció "Template context" de després). Per defecte, aquest és False.

allow_future
Un booleà que especifica si s'han d'incloure els objectes "futurs" en aquesta pàgina, s'ha descrit en la nota anterior.

Aquesta vista també utilitza un d'aquests arguments comuns descrits més anteriorment:

  • allow_empty
  • context_processors
  • extra_content
  • mimetype
  • template_loader
  • template_name
  • template_object_name

Nom de la plantilla

Si no s'expecifica template_name, aquesta vista usarà la plantilla per defecte /_archive_year.html.

Context de la plantilla

A més de l'extra_context, aquest context de plantilla també tindrà:

date_list
Una llista d'objectes datetime.date representant tots els mesos que hi ha objectes disponibles, d'acord amb el queryset. Aquests estaran ordenats ascendentment.

year
L'any indicat, en una cadena de quatre caràcter.

object_list
Si el paràmetre make_object_list és True, aquest contindrà una llista dels objectes disponibles per aquest any, ordenats pel camp data. Aquest nom de variable depèn del paràmetre template_object_name, que és 'object' per defecte. Si template_object_name és 'foo', aquest nom de variable serà foo_list.

Si make_object_list és False, object_list serà passat a la plantilla com una llista buda.

Arxius de Mes

La vista django.views.generic.date_based.archive_month proporciona una pàgina d'arxiu mensual mostrant tots els mesos disponibles en el mes indicat.

Exemple

Continuant amb el nostre exemple, creem vistes de mes que tindran un aspecte semblant a aquest:

(r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$', date_based.archive_month, book_info),

Arguments requerits

year
L'any de 4 dígits que serveix l'arxiu.

month
El mes que serveix l'arxiu, formatat d'acord amb l'argument month_format.

queryset
Un QuerySet d'objectes que servirà l'arxiu.

date_field
El nom del DateField o DateTimeField del model QuerySet que haurà d'usar-se en l'arxiu basat en dates per determinar els objectes de la pàgina.

Arguments opcionals

month_format
Una cadena de text de format que regula quin format utilitza el paràmetre month. Aquest hauria d'estar amb la sintaxi acceptada per la funció time.strftime de Python. Aquest està activat a "%b" per defecte, el qual és una abreviació del mes amb tres lletres (p.e. "jan", "feb", etc.). Per canviar-ho a números, utilitza "%m".

allow_future
Un booleà que especifica si s'han d'incloure els objectes "futurs" en aquesta pàgina, s'ha descrit en la nota anterior.

Aquesta vista també utilitza un d'aquests arguments comuns descrits més anteriorment:

  • allow_empty
  • context_processors
  • extra_content
  • mimetype
  • template_loader
  • template_name
  • template_object_name

Nom de la plantilla

Si no s'expecifica template_name, aquesta vista usarà la plantilla per defecte /_archive_month.html.

Context de la plantilla

A més de l'extra_context, aquest context de plantilla també tindrà:

month
Un objecte datetime.date representant el mes indicat.

next_month
Un objecte datetime.date representant el primer dia del pròxim mes. Si el pròxim mes és al futur, aquest serà None.

previous_month
Un objecte datetime.date representant el primer dia del mes anterior. A diferència de next_month, aquest mai serà None.

object_list
Una llista dels objectes disponibles en el mes indicat. Aquest nom de variable depèn del paràmetre template_object_name, que és 'object' per defecte. Si template_object_name és 'foo', aquest nom de variable serà foo_list.

Arxius de Setmana

La vista django.views.generic.date_based.archive_week mostra tots els objectes de la setmana indicada.

Nota
Django pensa que les setmanes comencen el Diumenge, per la raó arbitrària que Python també ho fa.

Exemple

Estàs mirant-te aquest patró?

(r'^(?P<year>\d{4})/(?P<week>\d{2})/$', date_based.archive_week, book_info),

Arguments requerits

year
L'any de 4 dígits que serveix l'arxiu (una cadena de text).

setmana
La setmana que serveix l'arxiu(una cadena de text).

queryset
Un QuerySet d'objectes que servirà l'arxiu.

date_field
El nom del DateField o DateTimeField del model QuerySet que haurà d'usar-se en l'arxiu basat en dates per determinar els objectes de la pàgina.

Arguments opcionals

allow_future
Un booleà que especifica si s'han d'incloure els objectes "futurs" en aquesta pàgina, s'ha descrit en la nota anterior.

Aquesta vista també utilitza un d'aquests arguments comuns descrits més anteriorment:

  • allow_empty
  • context_processors
  • extra_content
  • mimetype
  • template_loader
  • template_name
  • template_object_name

Nom de la plantilla

Si no s'expecifica template_name, aquesta vista usarà la plantilla per defecte /_archive_week.html.

Context de la plantilla

A més de l'extra_context, aquest context de plantilla també tindrà:

week
Un objecte datetime.date que representa el primer dia de la setmana indicada.

object_list
Una llista dels objectes disponibles en la setmana indicada. Aquest nom de variable depèn del paràmetre template_object_name, que és 'object' per defecte. Si template_object_name és 'foo', aquest nom de variable serà foo_list.

Arxius de Dia

La vista django.views.generic.date_based.archive_day mostra tots els objectes del dia indicat.

Exemple

Segueix atent:

(r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\d{2})/$', date_based.archive_day, book_info),

Arguments requerits

year
L'any de 4 dígits que serveix l'arxiu (una cadena de text).

month
El mes que serveix l'arxiu, formatat d'acord amb l'argument month_format.

day
El dia que serveix l'arxiu, formatat d'acord amb l'argument day_format.

queryset
Un QuerySet d'objectes que servirà l'arxiu.

date_field
El nom del DateField o DateTimeField del model QuerySet que haurà d'usar-se en l'arxiu basat en dates per determinar els objectes de la pàgina.

Arguments opcionals

month_format
Una cadena de text de format que regula quin format utilitza el paràmetre month. Mira els detalls explicats en l'apartat de month.

day_format
Com month_format, però amb el paràmetre day. Per defecte el seu valor és '%d' (dia del més com un número decimal, 01-31).

allow_future
Un booleà que especifica si s'han d'incloure els objectes "futurs" en aquesta pàgina, s'ha descrit en la nota anterior.

Aquesta vista també utilitza un d'aquests arguments comuns descrits més anteriorment:

  • allow_empty
  • context_processors
  • extra_content
  • mimetype
  • template_loader
  • template_name
  • template_object_name

Nom de la plantilla

Si no s'expecifica template_name, aquesta vista usarà la plantilla per defecte /_archive_day.html.

Context de la plantilla

A més de l'extra_context, aquest context de plantilla també tindrà:

day
Un objecte datetime.date representant el dia indicat.

next_day
Un objecte datetime.date representant el pròxim dia. Si el pròxim dia és al futur, aquest serà None.

previous_day
Un objecte datetime.date representant el dia anterior. A diferència de next_day, aquest mai serà None.

object_list
Una llista dels objectes disponibles en el dia indicat. Aquest nom de variable depèn del paràmetre template_object_name, que és 'object' per defecte. Si template_object_name és 'foo', aquest nom de variable serà foo_list.

Arxiu d'avui

La vista django.views.generic.date_based.archive_today mostra tots els objectes d'avui. És exactament el mateix que archive_day, excepte que els arguments year/month/day no s'usen, en canvi s'usa la data d'avui.

Pàgines de detall basats en data

La vista django.views.generic.date_based.object_detaul mostra una pàgina representant un objecte individual. Aquest es diferencia de la pàgina object_detail en les serves URL respectives; les vistes object_detail utilitzen URLs com /entries/<slug>, mentre aquesta utilitza URLs com /entries/2006/aug/27/<slug>/.

Nota
Si estàs utilitzant pàgines de detall basades en dates amb etiquetes (slug) en la URL, probablement també voldràs usar l'opció unique_for_date del camp etiqueta per validar que les etiquetes no estan duplicades en un únic dia. Mira l'Apèndix 2 per més detalls sobre unique_for_date.

Exemple

Aquest difereix (lleugerament) dels altres exemples en que cal proporcionar un ID o etiqueta per que Django pugui localitzar l'objecte en qüestió.

Com que l'objecte que estem utilitzant no té el camp etiqueta, utilitzarem la "una mica lletja" URL basada amb ID. En la pràctica, preferim utilitzar el camp etiqueta, però en interès per a la simplicitat ho farem així.

Afegim la següent URL:

(r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\d{2})/(?P<object_id>[\w-]+)/$', date_based.object_detail, book_info),

Arguments requerits

year
L'any de 4 dígits que serveix l'arxiu (una cadena de text).

month
El mes que serveix l'arxiu, formatat d'acord amb l'argument month_format.

day
El dia que serveix l'arxiu, formatat d'acord amb l'argument day_format.

queryset
Un QuerySet d'objectes que servirà l'arxiu.

date_field
El nom del DateField o DateTimeField del model QuerySet que haurà d'usar-se en l'arxiu basat en dates per determinar els objectes de la pàgina.

Aquest:
object_id
El valor de la clau principal de l'objecte.

o aquest:
slug
L'etiqueta de l'objecte indicat. Si li passes aquest camp, llavors l'argument slug_field (més avall) també serà requerit

Arguments opcionals

allow_future
Un booleà que especifica si s'han d'incloure els objectes "futurs" en aquesta pàgina, s'ha descrit en la nota anterior.

day_format
Com month_format, però amb el paràmetre day. Per defecte el seu valor és '%d' (dia del més com un número decimal, 01-31).

month_format
Una cadena de text de format que regula quin format utilitza el paràmetre month. Mira els detalls explicats en l'apartat de month.

slug_field
El nom del camp de l'objecte que conté l'etiqueta. És requerit si estàs utilitzant l'argument slug, però ha d'obviar-se si utilitzen l'argument object_id

template_name_field
El nom del camp de l'objecte el valor del qual és el nom de la plantilla a utilitzar. Això et permet guardar noms de plantilles en les teves dades. En altres paraules, si el teu objecte té un camp 'the_template' que conté una cadena 'foo.html', i template_name_field val 'the_template', llavors la vista genèrica d'aquest objecte utilitzarà la plantilla 'foo.html'.

És una mica rebuscat, però útil en molts casos.

Aquesta vista també utilitza un d'aquests arguments comuns descrits més anteriorment:

  • context_processors
  • extra_content
  • mimetype
  • template_loader
  • template_name
  • template_object_name

Nom de la plantilla

Si no s'expecifica template_name, aquesta vista usarà la plantilla per defecte /_detail.html.

Context de la plantilla

A més de l'extra_context, aquest context de plantilla també tindrà:

object
L'objecte. Aquest nom de variable depèn del paràmetre template_object_name, que és 'object' per defecte. Si template_object_name és 'foo', aquest nom de variable seria foo.

Nota
Aquestes vistes canviaran lleugerament quan Django acabi de revisar la seva arquitectura (actualment sota desenvolupament a django.newforms). Aquesta secció serà actualitzada en aquell moment.

El mòdul django.views.generic.create_update conté un conjunt de funcions per crear, editar i esborrar objectes.

Vista de crear objecte

La vista django.generic.create_update.create_object mostra un formulari per crear un objecte, re-dibuixa el formulari amb els erros de validació (si n'hi ha) i guarda l'objecte. Aquest utilitza els manipuladors automàtics que venen amb els models Django.

Totes aquestes vistes presenten formularis si s'accedeix amb un GET i processar l'acció requerida (crear/modificar/esborrar) si s'hi accedeix via POST.

Fixa't que totes aquestes vistes tenen una idea molt aspre per la seguretat. Encara que agafin un atribut login_required que si existeix restringiran l'accés a usuaris identificats, que és pel que serveix. No poden, per exemple, comprovar que l'usuari que edita un objecte és el mateix usuari que l'ha creat, ni validaran altres tipus de permisos.

La majoria de cops, tanmateix, aquestes característiques poden realitzar-se escrivint un petit embolcall al voltat de la vista genèrica; mira "estenent vistes genèriques", més avall, per saber-ne més sobre aquest tema.

Exemple

Si volem permetre als usuaris crear nous llibres en la teva base de dades, podríem fer quelcom així:

(r'^books/create/$', create_update.create_object, {'model' : Book}),

Arguments Requerits

model
El model Django de l'objecte que el formulari crearà.

Nota
Fixa't que aquesta vista agafa el model que es crearà, no un QuerySet (com en totes les vistes anteriors llista/detall/basat-data).

Arguments opcionalls

post_save_redirect
Una URL on la vista re-direccionarà després de guardar l'objecte. Per defecte, serà object.get_absolute_url().

Pot contenir un diccionari de cadenes formatades, que seran interpolades amb els atributs de l'objecte. Per exemple, podries utilitzar post_save_redirect="/polls/%(slug)s/".

login_requires
Un booleà que designa si un usuari ha d'estar identificat, per veure una pàgina i guardar els canvis. Aquests enganxa dins del sistema d'autenticació de Django. Per defecte, és False

Si és True, i un usuari no identificat intenta visitar aquesta pàgina o guardar el formulari, Django el redireccionarà a /accounts/login.

Aquesta vista també utilitza un d'aquests arguments comuns descrits més anteriorment:

  • context_processors
  • extra_content
  • mimetype
  • template_loader
  • template_name

Nom de la plantilla

Si no s'expecifica template_name, aquesta vista usarà la plantilla per defecte /_form.html.

Context de la plantilla

A més de l'extra_context, aquest context de plantilla també tindrà:

form
Una instància FormWrapper representant el formulari per modificar l'objecte. Això et permet referir-te als camps del formulari fàcilment en el sistema de plantilles.

Per exemple, si el model té dos camps, name i address:

<form action="" method="post">
<p><label for="id_name">Name:</label> {{ form.name }}</p>
<p><label for="id_address">Address:</label> {{ form.address }}</p>
</form>

Mireu el Capítol 7 per més informació sobre com treballar amb formularis.

Vista de modificar objecte

La vista django.generic.create_update.update_object és completament idèntica a la vista crear-objecte, però aquesta només modifica un objecte existent en comptes de crear-ne un de nou.

Exemple

Seguint l'exemple anterior, podríem proporcionar una interfície d'edició per un llibre amb aquesta URL:

(r'^books/edit/(?P<object_id>\d+)/$', create_update.update_object, {'model' : Book}),

Arguments Requerits

model
El model Django de l'objecte que el formulari crearà.

Aquest:
object_id
El valor de la clau principal de l'objecte.

o aquest:
slug
L'etiqueta de l'objecte indicat. Si li passes aquest camp, llavors l'argument slug_field (més avall) també serà requerit

Arguments opcionalls

slug_field
El nom del camp de l'objecte que conté l'etiqueta. És requerit si estàs utilitzant l'argument slug, però ha d'obviar-se si utilitzen l'argument object_id.

A més, aquesta vista pren tots els mateixos arguments opcionals de la vista de creació (a sobre), més l'argument comú template_object_name.

Nom de la plantilla

Si no s'expecifica template_name, aquesta vista usarà la plantilla per defecte /_form.html com en la vista de creació.

Context de la plantilla

A més de l'extra_context, aquest context de plantilla també tindrà:

form
Una instància FormWrapper representant el formulari per modificar l'objecte. Mira la creació d'objecte (a sobre) per més informació sobre aquest valor.

object
L'objecte original que serà editat (aquesta variable pot ser anomenada diferent si has proporcionat el argument template_object_name).

Vista esborrar objecte

La vista django.generic.create_update.delete_object també molt similar a les altres dues.

Si aquesta vista es demana amb un GET, es mostrarà una pàgina de confirmació (p.e. "realment vols esborrar aquest objecte?"). Si la vista s'envia amb un POST, l'objecte serà eliminat sense confirmació.

Tots els arguments són els mateixos que els de la vista de modificació, com el context; el nom de la plantilla per aquesta vista és /_confirm_delete.html

Estenent vistes genèriques

No hi ha preguntes sobre que utilitzar vistes genèriques es pugui augmentar substancialment el desenvolupament. En molts projectes, tantmateix, arriba un moment que les vistes genèriques no són suficients. De fet, la majoria de les preguntes fetes pels nous desenvolupadors de Django són sobre com fer vistes genèriques per una gama més gran de situacions.

Afortunadament, en gairebé tots els caos, hi ha formes simples d'estendre les vistes genèriques per tractar aquesta gama de casos. Aquestes situacions normalment entren dins un conjunt de patrons:

Afegint context extra

Sovint, simplement necessites mostrar informació extra que la que proporciona la vista genèrica. Per exemple, pensa que has de mostrar una llista de totes les editorials en una pàgina de detall d'un llibre; la vista genèrica object_detail proporciona el llibre al context, però sembla que no hi ha forma d'aconseguir una llista d'editorials per a aquesta plantilla.

Per hi és: totes les vistes genèriques tenen un paràmetre de contingut extra (extra_content). Aquest és un diccionar per a objecte extra que seran afegits al context de la plantilla. Així, per proporcionar la llista d'editorials en la vista de detall del llibre, hauràs d'usar un diccionari com aquest:

book_info = {
    "queryset"   : Book.objects.all(),
    "date_field" : "publication_date",
    "extra_context" : {
        "publisher_list" : Publisher.objects.all(),
    }
}

Aquesta publicaria una variable {{ publisher_list }} en el context de la plantilla. Aquest patró pot utilitzar-se per passar qualsevol tipus d'informació dins de la plantilla per la vista genèrica; és molt pràctic.

Filtres més complexos que les funcions d'embolcall

Una altra necessitat comuna és filtrar els objectes que es passen a una pàgina de llistat a partir d'alguna clau de la URL. Per exemple, mirar de proporcionar una interfície per navegar pels llibre per títol. Voldríem proporcionar URLs del tipus /books/by-title/a/, /books/by-title/b/, etc. -- una pàgina de llista per cada lletra de l'alfabet.

El problema sembla ser que aquesta vista genèrica no contempla la lectura de variables de la URL; si volem seguir el model de les URL passant-los-hi l'objecte object_list, hauriem de crear 25 pàgines per exhibir tots els llibres. Encara que podríem escriure 26 diccionaris (cadascun amb un queryset diferent), això seria una ximpleria. La tècnica correcta implica escriure una funció d'embolcall simple al voltant de la vista genèrica.

En el nostre exemple de la navegació alfabetica, començaríem afegint una petita URLconf:

from bookstore.views import browse_alphabetically

urlpatterns = patterns('',
    # ...
    <b>(r'^books/by-title/([a-z])/$', browse_alphabetically)</b>
)

Com pots veure, aquest enllaça un conjunt de URLs a la funció browse_alphbetically, així mirem com s'hauria d'escriure aquesta funció:

from bookstore.models. import Book
from django.views.generic import list_detail

def browse_alphabetically(request, letter):
    return list_detail.object_list(
        request,
        queryset = Book.objects.filter(title__istartswith=letter),
        template_name = "bookstore/browse_alphabetically.html",
        extra_context = {
            'letter' : letter,
        }
    )

És així!

Això funciona perquè no hi ha res d'especial en les vistes genèriques -- només són funcions Python. Com qualsevol funció vista, les vistes genèriques esperen un cert conjunt d'arguments i retornen objectes HttpResponse. Així, és increïblement fàcil d'embolcallar una petita funció al voltant d'una vista genèrica que fa una mica de feina abans -- o després; mirar-ho més avall -- capturant coses de la vista genèrica.

Nota
Fixa't que en l'exemple anterior, hem passat la lletra actual per a que sigui mostrar en el extra_context. Això és normalment una bona idea en embolcalls d'aquesta naturalesa; permet que la plantilla conegui quina lletra s'està actualment mostrant.

Fixa't també (mentre no sigui en el tema de les plantilles) que hem passat un nom de plantilla personalitzat. Sinó, intentaria usar la mateixa plantilla object_list, que podria entrar en conflicte amb altres vistes genèriques.

Executar treball extra

L'últim patró comú, veuràs que realitza alguna feina extra abans o després de cridar la vista genèrica.

Imagina que tens un camp last_accessed en el teu objecte Author que utilitzem per mantenir una traça de l'última vegada que algú ha mirat aquest autor. La vista genèrica object_detail, per descomptat, no sabrà res sobre aquest camp, però un cop l'hem obtingut podríem fàcilment escriure una vista personalitzada per mantenir aquest camp actualitzat.

Primer, necessitem modificar un tros de la vista de detall de l'autor en la nostra URL per a que apunti a una vista personalitzada:

from bookstore.views import author_detail

urlpatterns = patterns('',
    #...
    <b>(r'^authors/(?P<author_id>d+)/$', author_detail),</b>
)

Llavors haurem d'escriure la funció embolcall:

import datetime
from bookstore.models import Author
from django.views.generic import list_detail
from django.shortcuts import get_object_or_404

def author_detail(request, author_id):
    # Look up the Author (and raise a 404 if she's not found)
    author = get_object_or_404(Author, pk=author_id)

    # Record the last accessed date
    author.last_accessed = datetime.datetime.now()
    author.save()

    # Show the detail page
    return list_detail.object_detail(
        request,
        queryset = Author.objects.all(),
        object_id = author_id,
    )
Nota
Aquest codi no funcionarà ara mateix, excepte que afegeixis el camp last_accessed al teu model Author.

Podem utilitzar un llenguatge semblant per alterar la resposta retornada per una vista genèrica. Si esperem proporcionar una versió de text pla descarregable de la llista d'autors, podríem usar una vista com aquesta:

def author_list_plaintext(request):
    response = list_detail.object_list(
        queryset = Author.objects.all(),
        mimetype = "text/plain",
        template_name = "bookstore/author_list.txt"
    )
    response["Content-Disposition"] = "attachment; filename=authors.txt"
    return response

Això funciona perquè les vistes genèriques retornen objectes HttpResponse simples que poden ser tractats com a diccionaris per a activar capçaleres HTTP. Aquest Content-Disposition, indica al navegador que descarregui i guardi una pàgina en comptes de mostrar-la en el navegador.

Què és el pròxim?

Fins ara, hem tractat el motor de plantilles com una eina estàtica que pots utilitzar per imprimir el teu contingut. És cert que la majoria de cops l'utilitzarà així, però el motor de plantilles és actualment més ampliable.

En el pròxim capítol aprofundirem dins de la forma de treballar de les plantilles Django, mostrat totes les coses interessants que poden fer-s'hi.

Endavant, camarades!