Avaluació pererosa a Python: un exemple amb Django


Escrit per Aaloy a 04 de September , 2008 a les 3:16 p.m.

Aprofitant que tenc vacances (eps! una setmana i ja s'acaben) aprofitaré per comentar un codi que serveix tant per entendre un poc més Python com per fer feina amb Django. La idea és del blog themorge.org


class PersonForm(ModelForm): "Simple form for the Person model" class Meta: model = Person

def edit(request,id=None): """Edits the Person model""" formulario = PersonForm(request.POST or None, instance = id and Person.objects.get(id = id) ) if request.method == 'POST': if formulario.is_valid(): persona = formulario.save() return HttpResponseRedirect('/fitxa/guardada/%s/'%persona.id) return render_to_response('edit.html', {'formulario': formulario})

Això representa un formulari d'edició amb Django (versió trunk). Tenim definit als models de l'aplicació una classe Person i el que volem és crear un formulari d'edició a partir d'aquest model.

A la classe PersonForm podem veure com hem creat el formulari a partir de la definició del model. Podem personalitzar el formulari afegint-hi validacions específiques, canviar la manera que s'edita etc, però si volem una cosa bruta i ràpida amb quatre línies en sortim (sí, la documentació sí és necessària).

Definim ara la part d'edició en sí, en el meu cas l'he anomenada edit, i fa referència a una plantilla edit.html, que bàsicament conté

       <form action="." method="post">
           <table>
               {{formulario}}
           </table>
           <button name="submit" value="submit"  type="submit">Send</button>
           <button name="reset" value="reset" type="reset">Reset</button>
       </form>
   

L'embolcall de l'html ho deixo com a exercici pel lector.

Anem a veure què passa quan a través de la url anam a parar a l'edit. Tenim dos casos possibles inicialment, que vulguem afegir un mou registre o que en volguem modificar-ne un ja existent. En el primer cas se'ns ha de mostrar un formulari en blanc, i en el segon un formulari amb les dades omplertes del l'objecte Persona agafat de la base de dades per l'ORM de Django.

Els urls que jo he definit són

     (r'^edit/(?P\d+)/$','edit'),
     (r'^add/$','edit'),

Com veim hi ha dues urls que apunten al mètode edit, la primera agafa l'id com a paràmetre, per la qual coses les urls serien de la forma /edit/10/ i la segona no agafa cap paràmetre i per tant queda com /add/. De fet podríem no haver fet la distinció entre edit i add, però si la feim el codi html ens quedarà molt més bo de llegir, més semàntic.

Estudiem el cas add. Quan entrem al mètode edit, com que no li passam l'id agafarà el valor per defecte, a saber None ja que així ho me definit al mètode, i ara comença la part interessant...

Definim un objecte de tipus PersonForm, la inicialització de la classe agafa dos paràmetres, el primer són els valors inicials del formulari i el segon és la instància de la classe que volem modificar.

Quan seleccionam editar un registre o afegir-ne un de nou, el que feim és un GET i quan guardam el registre hem definit al nostre codi HTML que el que farem és un POST.

Així doncs, ara hem fet un GET. L'operador or en Python funciona de la següent manera: x or y primer avalua x, si x és vertader retorna x i si no avalua y i retorna el resultat. Fixem-nos que deim que és una avaluació pererosa perquè si x dóna vertader, y mai s'arribarà a avaluar. Com que hem fet un GET la primera expressió és False i n'avaluarà la segona, amb la qual cosa obtenim un preciós None com a resultat de la inicialització de valors.

Anem ara a la segon part, la que ens defineix la instància, en aquest cas tenim un and. L'and funciona de la següent manera: x and y primer avalua x si x és fals llavors retorna el seu valor i si no s'avalua y i es retorna el seu valor. En el cas doncs de que x sigui fals ja no s'avaluarà y.

En el nostre cas hem passat el valor id=None llavors ja no itentarà ni crear una instància de l'objecte, senzillament passarà None com a valor de la instància, és a dir, res, i això indicarà a Django que es tracta d'un registre nou.

Per tant, quan hem entrat via add que que obtenim és un formulari buid. Com que hem entrat per GET l'if no s'avaluarà i Django ens presentarà una plana html amb un formulari buid.

Suposem ara que feim un /edit/2/, en aquest cas també haurem passat per GET però el valor de l'id serà 2.

formulario llavors tendrà None com a valors inicials per la mateixa raó que abans, però ara el primer terme de l'and és vertader i se n'avalua el segon, això fa que obtinguem com a valor per la instància l'objecte Person que té id igual a 2. En aquest cas tendrem un formulari ple amb els valors del registre i Django ens presentarà un formulari amb les dades de l'objecte com a valors i lligarà la instància al formulari (això significa que podrem fer formulario.save() per guardar el registre).

Molt bé, ja tenim un formulari, ple o buid, tant fa, ara el que feim és afegir o modificar dades i pitjam damunt l'opció de guardar. Això farà un post i cridarà a la mateixa url (el punt a l'action així ens ho garanteix), això significa que per a la inserció l'id serà None i per afegir l'id serà un número, 2 en el nostre cas.

Ara entram per POST, la qual cosa fa que la primera part de l'or sigui vertadera, amb la qual cosa el formulari tindrà com a valors inicials el que hagem posat, perquè això? dons per si no hem passat la validació del formulari, si anam per POST i el formulari no passa la validació, anirem novament a la mateixa plantilla, però ara tindrem com a valors del formulari el que hem passat, és a dir, si no passam la validació tornarem a tenir un formulari ple amb les dades que hem escrit.

És important fixar-se que les dades inicials a diferència de les dades que passem per la instància no necessàriament han de ser vàlides, no passen pels mecanismes de validació de Django, i això és el que ens permet recuperar tot el que hem escrit encara que estigui malament segons la validació.

Seguim, si hem entrat per edit l'id serà None i per tant ja no es crea cap objecte Person, si hem entrat per add l'id tindrà valor i s'avaluarà el segon terme de l'and amb la qual cosa haurem recuperat el registre de tipus Person que té id igual al nombre passat i l'haurem lligat al formulari.

Com que és un POST i passam la validació el que se fa és guardar el registre (si estava inicialitzat farà un update, sinó farà un insert a la base de dades i ens retornarà la instància de la classe Person que s'ha guardat.

Ara, que ja s'ha guardat sols ens queda fer un redirect de manera que evitem problemes amb dobles pitjades i refrescs varis. En el meu cas vaig a una url que em presentarà la fitxa que tot just acabam de crear/modificar.

Esper que aquest exemple us hagi agradat tant com a mi quan ho vaig veure. És tot un exemple de l'expressivitat de Python i del ben pensat que està Django. Però el més important de tot d'aquesta història és que sempre es pot aprendre alguna cosa i que per aprendre és important dedicar temps a llegir codi dels altres.


Traducciones/Translations by apertium

1 comentari, 0 trackbacks (URL) , Tags: Python Django


Django 1.0


Escrit per Aaloy a 04 de September , 2008 a les 8:48 a.m.

La versió 1.0 de Django fa sis hores més o menys que ha sortit del forn, es pot veure ja el comunicat oficial a la plana web del projecte.

Els números són impressionants, de de la darrera versió estable s'han fet 4.000 commits, s'han resolt 2.000 errors i s'han afegit o llevat prop de 350.000 línies de codi. I el que trob un factor diferenciador de Django: s'han afegit 40.000 línies noves de documentació, pocs bastiments de codi obert dediquen tants esforços a la documentació.

Se m'ha acudit passar-li el sloccount a trunk del projecte

SLOC DirectorySLOC-by-Language (Sorted)
46235 django python=46235
24683 tests python=24683
341 docs python=341
80 examples python=80
56 top_dir python=56
16 scripts sh=16
0 extras (none)
0 patches (none)

Totals grouped by language (dominant language first):

python: 71395 (99.98%)
sh: 16 (0.02%)

Total Physical Source Lines of Code (SLOC) = 71,411

Development Effort Estimate, Person-Years (Person-Months) = 17.68 (212.16) (Basic COCOMO model, Person-Months = 2.4 * (KSLOC1.05))

Schedule Estimate, Years (Months) = 1.60 (19.15)

(Basic COCOMO model, Months = 2.5 * (person-months0.38)) Estimated Average Number of Developers (Effort/Schedule) = 11.08

Total Estimated Cost to Develop = $ 2,388,334

Si a més contam css, javascript i l'html amb una altra eina

 ./cloc-1.04.pl  --exclude-dir=.cvs,.svn --no3 .

    http://cloc.sourceforge.net v 1.04  T=11.0 s (80.8 files/s, 10177.7 lines/s)
    -------------------------------------------------------------------------------
    Language                     files          blank        comment           code
    -------------------------------------------------------------------------------
    Python                         739          15302           8184          83136
    HTML                           100            364             15           1725
    Javascript                      15            107            269           1547
    CSS                             15             83             82            505
    XML                             10             49              8            431
    make                             1             12              4             54
    SQL                              8              1              9             40
    Bourne Shell                     1              4              7             17
    -------------------------------------------------------------------------------
    SUM:                           889          15922           8578          87455
    -------------------------------------------------------------------------------

Hem d'agraïr la feina feta als desenvolupadors principals de Django i a la comunitat que s'ha format al voltant per tot l'esforç i la bona feina feta.

Django s'ha convertit per mi en un factor diferenciador en el que fa a productivitat i velocitat de desenvolupament, cada nova millora ha estat sempre orientada fer les coses més naturals per al programador, més pythoniques, molt en la línia del llenguatge de programació en el qual està fet Django, el Python.

Ara sols resta anar adaptant el codi per a incorporar les millores i les noves maneres de fer feina. Els canvis dels darrers mesos han estat tan grans i tan ràpids que sovint costava anar seguint el fil, però el resultat és un bastiment com per a sentir-se orgullosos.


Traducciones/Translations by apertium

1 comentari, 0 trackbacks (URL) , Tags: Python Django