El Blog de Trespams

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

Django class based views (V) - CRUD

Creant un CRUD

En aquesta cinquena part veurem com podem crear tot el relacionat amb un manteniment, el famós CRUD (Create, Retreive, Update, Delete).

La part de Retreive ja l'hem vista a l'article anterior, però hi tornarem per a que ens quedi un exemple complet.

Partirem del següent model:

class Sample(models.Model):
"""this is just a sample model"""
slug = models.SlugField(max_length=50, unique=True)
name = models.CharField(max_length=100)
ammount = models.IntegerField()
comments = models.TextField(blank=True, null=True)

class Meta:
verbose_name = 'Sample'
verbose_name_plural = 'Sample'

def __unicode__(self):
return self.name

Django a més de DetailView ens proporciona les següents vistes ja construïdes per fer aquest tipus de tasques:

  • CreateView que gestiona la creació
  • UpdateView que gestiona l'actualització
  • DeleteView que gestiona l'esborrat

Comencem!

Creació

Definim primer la url

url(r'^tutorial/sample/create/$', SampleCreateView.as_view(), name='tutorial_create_sample'),

Hem anomenat a la nostra classe SampleCreateView així que la definirem al views.py

from django.views.generic.edit import CreateView
from main.models import Sample


class SampleCreateView(CreateView):
model = Sample

Amb això Django ja ens crearà internament un formulari i l'intentarà presentar a una plantilla que es construeix amb el nom del model i el sufixe _form, és a dir, en el nostre cas sample_form.html passant com a variable de context el formulari creat form

Si volem fer via amb :

<form action="." method="post" accept-charset="utf-8">                                                                                                                                                   {% csrf_token %} 
<table> {{form}} </table> <p><input type="submit" value="Save &rarr;"></p> </form>

ja ens anirà bé. Django ja se n'encarrega de validar el formulari contra el nostre model. És a dir, si posam quelcom que no sigui un nombre sencer a amount ens generarà un error.

Si creau la plantilla i posau dades vàlides i intentau guardar us donarà un error: "No URL to redirect to. Either provide a url or define a get_absolute_url method on the Model.", poc a poc i ara hi anirem a això.

Mostram l'objecte

Encara que ja ho vàrem veure com es feia al post anterior, per completitud, ho farem també ara:

La url:

url(r'^tutorial/sample/retrieve/(?P<pk>\d+)/$', SampleView.as_view(), name='tutorial_view_sample'),

i al views.py

class SampleView(DetailView): 
model = Sample

Recordau l'error del que hem parlat abans? Doncs el que farem és modificar el model per definir el `get_absolute_url, també podíem haver definit success_url o sobreescrit get_success_url però això ja ho vàrem veure, així que variarem un poc.

Modificam el nostre model

class Sample(models.Model):
"""this is just a sample model"""
slug = models.SlugField(max_length=50, unique=True)
name = models.CharField(max_length=100)
ammount = models.IntegerField()
comments = models.TextField(blank=True, null=True)

class Meta:
verbose_name = 'Sample'
verbose_name_plural = 'Sample'

def __unicode__(self):
return self.name @ models.permalink

def get_absolute_url(self):
return ('tutorial_view_sample', [self.id, ])

També podíem haver fet el mateix fent servir l'slug, amb la qual cosa tindríem urls més amigables. Per això hem de canviar tant la url com el get_absolute_url

class Sample(models.Model):
"""this is just a sample model"""
slug = models.SlugField(max_length=50, unique=True)
name = models.CharField(max_length=100)
ammount = models.IntegerField()
comments = models.TextField(blank=True, null=True)

class Meta:
verbose_name = 'Sample'
verbose_name_plural = 'Sample'

def __unicode__(self):
return self.name @ models.permalink

def get_absolute_url(self):
return ('tutorial_view_sample', [self.slug, ])

i la url:

url(r'^tutorial/sample/retrieve/(?P<slug>[-\w]+)/$', SampleView.as_view(), name='tutorial_view_sample'),

Què fa el permalink? doncs, com veis, crea una url per al nostre objecte a partir del nom que li hem donat a la url que serveix per visualitzar-ho.

Això ens permet no anar posant les urls a foc, sinó tenir-les definides amb un nom dins tota l'aplicació.

Si ara provau de fer anar el formulari veureu que ja funciona. Podem crear-lo i en guardar mostrar el resulta. Ja tenim dues de les quatre lletres, anem a veure les que falten.

Actualització

L'actualització és també molt senzilla. Farem servir UpdateView però a diferència de la creació a la url li hem de passar bé la clau primària de l'objecte o bé l'slug (sempres suposant que aquest sigui únic).

la url:

url(r'^tutorial/sample/update/(?P<slug>[-\w]+)/$', SampleUpdateView.as_view(), name='tutorial_update_sample'),

pràcticament semblant a la de visualització, i ara a la part de la vista bastarà fer:

from django.views.generic.edit import UpdateView


class SampleUpdateView(UpdateView):
model = Sample

Ara sols ens falta lligar la url per poder anar a l'edició de l'objecte, ho podem fer directament des de la barra de navegació, però millor posar-ho també a la plana web, per exemple amb un link a la plantilla de visualització per a que ens dugui a l'edició de l'objecete. Ja que hi sóm posarem també el link de creació. Molt resumidament, el nostre sample_detail.html quedaria de la forma:

<!DOCTYPE html PUBLIC  "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> 
<html xmlns=""http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>test</title>
</head>
<body>
<h1>Sample Detail</h1>
{{sample.slug}}<br/>
{{sample.name}}<br/>
{{sample.ammount}}<br/>
{{sample.comments}}<br/>
<a href="{% url tutorial_update_sample sample.slug %}">Update</a>|<a href="{% url tutorial_create_sample %}">Create</a>
</body>
</html>

Eliminació

Ja hem arribat a la darrera lletra de l'acrònim. Per a esborrar un objecte Django ens proporciona la vista DeleteView. Abans d'esborrar es convenient demanar confirmació i a la implementació de Django es té això en compte.

La url serà de la forma:

url(r'^tutorial/sample/delete/(?P<slug>[-\w]+)/$', SampleDeleteView.as_view(), name='tutorial_delete_sample'),

i a la view.py

from django.views.generic.edit import DeleteView


class SampleDeleteView(DeleteView):
model = Sample

si volem que tot funcioni per defecte, hem de crear una plantilla construida amb el nom del model i el sufixe "_confirm_delete".

En aquesta plantilla hem de demanar la confirmitat per esborrar el registre, enviant-ho a la mateixa URL d'esborrat però fent un POST. És a dir la url amb GET presenta la confirmació i amb POST fa l'acció.

<!DOCTYPE html PUBLIC"-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" > 
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>test</title>
</head>
<body>
<h1>Sample Delete</h1>
{{sample.slug}}<br/>
{{sample.name}}<br/>
{{sample.ammount}}<br/>
{{sample.comments}}<br/>
<p>Are you sure?</p>
<form action="." method="post"accept-charset="utf-8">
{% csrf_token %}
<p><input type="submit"value="Delete &arr;"></p>
</form>
<p><a href="{% url tutorial_view_sample sample.slug %}">Return</a>
</body>
</html>

A l'actualització o a la creació no feia falta dir-li a Django on volíem anar, per defecte anava a la visualització de l'objecte. Ara l'estam esborrant, així que no hi ha objecte. Així que obligatòriament li hem de donar la url a la que ha d'anar en cas que l'objecte s'hagi eliminat. Ho podem enviar a una plana amb el llistat de tots els registres, però com que encara no hem vist com es fa, ara per ara l'enviarem al formulari de creació.

class SampleDeleteView(DeleteView): 
model = Sample
success_url = reverse_lazy('tutorial_create_sample'

I ja tenim el CRUD complet. Ens falta poder visualitzar un llistat paginat d'objectes i fer algunes accions bàsiques amb formularis. Ho veurem al proper apunt.

blog comments powered by Disqus