Consoles per Python
Escrit per Aaloy a 08 de March , 2010 a les 8:08 p.m.
Quan hom comença amb Python qualsevol ajuda és benvinguda i quan ja en saps un poc més llavors el que cerques és poder provar coses ràpid, flexibilitat i eines potents.
Sigui com sigui un dels avantatges de Python com a llenguatge de programació interpretat és que ens proporciona una consola de comandaments que ens permet provar les coses d'una manera pràcticament immediata. Tot i això, com us dic, quan comences a aprendre'n la consola que hi ha per defecte potser no és el més amigable del món.
Us presento unes quantes consoles més per poder triar i remenar:
bpython
És una consola molt amigable per la gent que comença: té autocompletat per defecte i ens mostra la documentació de les funcions que anam teclejant. Ens permet copiar el nostre codi a Pastebin, amb la qual cosa ens facilita la tasca de comentar el que surt (o no surt) amb altres persones. Té també una versió per gtk (bconsole-gtk) i s'integra amb Django fent servir eines de tercers. És ideal per a començar a jugar amb l'entorn i aprendre la sintaxi de les comandes.
dreampie
És també una shell força interessant per la gent que comença, surt del típic prompt i presenta una secció on es pot anar introduint el nostre codi. Amb ctrl+intro el codi passa a la shell i s'executa. És multiplataforma i s'integra amb matplotlib (pels qui necessitin fer gràfiques). Com a cosa interessant, ens permet guardar la feina en html, ideal per muntar tutorials.
pyShell
Junt amb Pycrust són utilitats que podem trobar al paquet wxPython. Tenen autocompletat i mostren la documentació. Són consoles potents però requereixen tenir instal·lat wxPython. M'agrada PyCrust perquè et mostra un poc les interioritats de l'intèrpret de Python, té una secció anomenada namespace on pots veure tot l'espai de noms que hi ha carregat i navegar-hi. Per exemple fer un import os posa el paquet os a l'espai de nom i podem moure'ns i veure'n les funcions que té, constants i la documentació.
ipython
La meva preferida. Una consola potent, gairebé pot reemplaçar una shell per les tasques més habituals. Té resaltat de sintaxi i autocompletat, però ja has de saber un poc més el que estàs cercant. S'integra molt bé amb Django i permet executar directament comandes de shell. El manual és molt complet i dóna una idea de la potència de la consola.
idle
Python ja ve amb les bateries incloses. A més de la consola habitual també podem trobar l'idle una consola gràfica i editor. Té resaltat de sintaxi i autocompletat. Li han fet una bona rentada de cara darrerament i també és una opció a considerar. A més recordau que és a més un editor força complet per Python.
Traducciones/Translations by apertium
2 comentaris, 0 trackbacks (URL) , Tags: Python
Vim IDE per Django i Python
Escrit per Aaloy a 17 de February , 2010 a les 8:18 p.m.
Encara que faig servir distints editors i entorns integrats (IDE) per programar en Python i Django hi ha sempre la constant de retornar cap a Vim i gVim.
La cosa està però, en que per al desenvolupament normal no vull renunciar a un parell de coses que fan la vida més fàcil:
- Resaltat de sintaxi amb colors personalitzables i/o una paleta de colors còmoda per fer-hi feina.
- Autocompletat (dins cert límits, que això és un llenguatge dinàmic) i ajuda integrada.
- Plantilles per no haver d'escriure molt. Per exemple els shebangs, o els models de Django.
- Distints tipus de tabulació segons el llenguatge, quatre per Python, però 2 per HTML i Javascript.
- Possibilitat de tenir oberts molts arxius a la vegada i accedir-hi fàcilment
- Navegació pel sistema d'arxius integrada
I poca cosa més. Després quant més potent sigui l'editor millor, i per això Vim n'és de potent!! El problema és que ja m'agradaria poder fer servir amb agilitat un 20% de les seves capacitats.
En la meva recerca de l'editor perfecte he anat modificant el .vimrc i afegint plugins diversos, i configuracions que anat trobant d'aquí i d'allà. Per si a algú li va bé, he posat el meu .vimrc i .vim amb els plugins a l'appusedjango. Ja me contareu!
Eines per a la isntal·lació de plugins
Si feis un apt-get vim-addons obtindreu una petita utlitat que us permetrà veure quins plugins teniu instal·lats al vostres sistema i activar-los pel vostre usuari. En el meu cas tenc:
bufexplorer installed markdown-syntax installed matchit installed python-indent installed python_bike installed supertab installed surround installed taglist installed utl installed winmanager installed xmledit installed
En local (i instal·lats a mà) tenc també:
- ftplugin
- nerdtree_plugin
- snippetsEmu
- taglist
- mathit
- supertab
- vcssvn
Hi ha altres plugins interessants com el nerdcommenter i altres, però encara m'he d'anar acostumant al altres.
Referències
La veritat és que em costa dir d'on ho he tret tot, la configuració és una feina orgànica, he anat agafant coses d'aquí i d'allà, així que pos els darrers consultats.
Disclaimer: NO sóc cap expert amb vim, així que moltes coses van per assaig i error.
Download
-
El subversion: http://code.google.com/p/appfusedjango/source/browse/#svn/trunk/myvim
-
El .vimrc
- El .vim
Al svn trobareu un .vimrc que heu de posar al vostre home i un arxiu comprimit amb .vim que conté plugins, plantilles i demés, descomprimiu-lo també al vostre home.
No he de recordar la impirtància de fer còpies de seguretat de la configuració antiga abans de res, veritat?
Pels debianites i ubuntaires
Per a tenir l'entorn funcional necessitareu instal·lar
- sudo aptitude ctags
- sudo aptitude vim-addons-manager
- sudo aptitude vim-python (segons versions...)
comprovat per bibigeek (gràcies!) pels ubuntaires amb PPC com jo, no hi ha vim-python i convé recompilar vim amb suport per Python.
Esper que us sigui d'utilitat!
Traducciones/Translations by apertium
2 comentaris, 0 trackbacks (URL) , Tags: Python Django
Ressenya de creant Bits, el déjà vu
Escrit per Aaloy a 30 de January , 2010 a les 10:41 a.m.
El segon creant bits dedicat a la introducció de Python i Django d'ahir va a tornar aplegar un bon nombre de gent interessada per la programació i per Python i Django.
Cares conegudes i gent que vaig poder desvirtualitzar. Em va fer especial il·lusió poder desvirtualitzar Guillem, ja que per un motiu o altre mai ens havíem pogut trobar personalment.
Aquesta vegegada preferírem no allargar molt la jornada i no es donà la xerrada damunt la posada en producció d'aplicacions Django. La passada jornada En Bernat va tenir molt poc temps i acabarem molt tard, així que ho hem deixat per a una millor ocasió.
Aquest pic el consum de gominolas per part dels assistents va ser menor, lluny del rècord de kilo i busques de l'altra vegada. :-P La idea és que si algú s'avorreix al manco se n'endurà un sabor dolç de boca.
Entre l'anecdotari comentar el mal cos que se'ns quedà a tots quan un tassó d'aigua va vessar damunt un portàtil Macbook Pro nou de trinca. Després de netejar-lo va tornar a la vida i esper que segueixi així. Hi va haver un segon intent de tragèdia, quan el que es va vessar va ser cafè i no aigua, afortunadament aquest cop no va tocar el portàtil.
Sols me queda agraïr l'assistència de tots i especialment dels companys que donàren l'assistència tècnica i ajuda. Esper que tothom se n'anàs amb una millor idea de la que tenia a l'entrada damunt el que és Python, el que es pot fer i de la potència de Django per al desenvolupament web.
Ara a encalentir motors per a la xerrada de Ricardo al proper creant bits.
Traducciones/Translations by apertium
7 comentaris, 0 trackbacks (URL) , Tags: Python Django
FireLogger per Python
Escrit per Aaloy a 15 de January , 2010 a les 3:42 p.m.
Quan hom fa feina amb Django una de les primeres coses que aprèn és a mirar la consola del servidor de desenvolupament. Al la consola hi apareixen els missatges d'error i els logs bé en forma de prints o com a logs de Python.
Convé evitar fer prints i fer servir els logs. Aprofitarem el funcionament del logger per tal de discrimitar els tipus de log i distingir entre els missatges que volem que es mostrin sols en depuració (DEBUG), errors o informatious.
Una configuració molt bàsica del logs és la que propòs a projecte base d'appfusedjango, molt ràpidament:
Al properties.py o al settings configuram el sistema de log
1 2 3 4 5 | import logging logging.basicConfig( format="%(asctime)s-%(levelname)s-%(name)s-%(lineno)s-%(message)s", level = logging.DEBUG, ) |
i a cada arxiu on el volguem fer servir
1 2 | import logging log = logging.getLogger(__name__) |
Això ens permte configurar a un sols lloc el nivell de log que volguem i a més saber des d'on s'estan generant els missatges.
Com a retruc, a més ens servirà per poder mostrar els logs a la consola del Firebug gràcies a l'aplicació FireLogger.
Aquesta aplicació té una instal·lació en dues parts, ja que hem d'instal·lar el plugin de Firefox que hi trobareu a la plana (la versió 0.7 en el moment d'escriure això) i després instal·lar les llibreries Python necessàries.
La plana recomana fer servir easy_install però en aquests moments el paquet que hi ha al PyPi està desactualitzat així que millor instal·lar-ho a mà:
sudo easy_install paver sudo easy_install jsonpickle git clone git://github.com/darwin/firepython.git cd firepython sudo python setup.py install
Amb això a una Ubuntu basta. Una vegada insta·lat anirem a la nostra palicació Django i a la secció del MIDDLEWARE_CLASSES afegirem
firepython.middleware.FirePythonDjango
Podem obrir ara la consola de Firebug i trobarem una nova secció anomenada Logger. Aquí apareixeran els missatges de Log de la nostra aplicació. Podem filtrar per la criticitat del log i a la mateixa vegada tenim tota la potència del Firebug per a la depuració de l'aplicació.
Una bona eina per tenir al caixó de les de desenvolupament i depuració.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python Django
Creant Bits, el déjà vu
Escrit per Aaloy a 07 de January , 2010 a les 9:24 p.m.
Em complau anunciar una segona edició de Creant Bits destinada a tots aquells i aquelles que no poguéreu assistir a la primera.
Els contingut seran bàsicament els mateixos, en tot cas mirarem de resoldre algunes mancances de la primera presentació, però en un 99% serà tot el mateix:
- Introducció bàsica al llenguatge Python, amb exercicis.
- Introducció a Django: arquitectura i possibilitats
- Instal·lació d'una aplicació Django a Apache.
La sala serà la mateixa que a la presentació anterior.
Creant Bits, el déjà vu
29 de gener de les 16:00 a les 21:00
Sala de Formació - Parc Bit
Pensau a dur el portàtil carregat amb el Python instal·lat. Hi ha connexió inhalàmbrica a la sala i el Parc Bit ens deixa un projector.
La sala té una capacitat per a 20 persones màxim. Per apuntar-vos deixau un comentari a aquest apunt.
Per cert, aquesta vegada tampoc hi ha catering! :)
Traducciones/Translations by apertium
23 comentaris, 0 trackbacks (URL) , Tags: Python Django APSL
Si House fos programador ...
Escrit per Aaloy a 04 de January , 2010 a les 7:35 p.m.
Ahir estava mirant la presentació de James Bennet a la DjangoCon anomenada "UR DOIN IT WRONG" i me'n vaig adonar que feia referència a una sèrie de màximes tipus:
#11919 No. You must believe the ERROR MESSAGE. You MUST believe the error message.
La conferència és molt bona, us la recoman. El cas, però, és que em va picar la curiositat i vaig seguir l'enllaç fins a arribar a una entrada de comp.lang.perl.misc del març del 2002 on Mark Jason Dominus feia una relació de consells que ell tenia a un arxiu anomenat File of Good Advice.
Les màximes, encara que plenes de sentit comú, tenen una mala llet considerable, i m'han recordat al nostre metge de la tele favorit. Supòs que no desapareixeran de la xarxa, però per si un cas les torn a escriure aquí. Ha passat temps, però la majoria són perfectament aplicables! Esper que les disfruteu tant com jo ho he fet.
#11900 You cannot just paste code with no understanding of what is going on and expect it to work. #11901 You can't just make shit up and expect the computer to know what you mean, Retardo! #11902 You said it didn't work, but you didn't say what it would have done if it *had* worked. #11903 What are you really trying to accomplish here? #11904 Who the fuck cares which one is faster? #11905 Now is the time in our program where you look at the manual. #11906 Look at the error message! Look at the error message! #11907 Looking for a compiler bug is the strategy of LAST resort. LAST resort. #11908 Premature optimization is the root of all evil. #11909 Bad programmer! No cookie! #11910 I see you omitted $! from the error message. It won't tell you what went wrong if you don't ask it to. #11911 You wrote the same thing twice here. The cardinal rule of programming is that you never ever write the same thing twice. #11912 Evidently it's important to you to get the wrong answer as quickly as possible. #11913 Gee, I don't know. I wonder what the manual says about that? #11914 Well, no duh. That's because you ignored the error message, dimwit. #11915 Only Sherlock Holmes can debug the program by pure deduction from the output. You are not Sherlock Holmes. Run the fucking debugger already. #11916 Always ignore the second error message unless the meaning is obvious. #11917 Read. Learn. Evolve. #11918 Well, then get one that *does* do auto-indent. You can't do good work with bad tools. #11919 No. You must believe the ERROR MESSAGE. You MUST believe the error message. #11920 The error message is the Truth. The error message is God. #11921 It could be anything. Too bad you didn't bother to diagnose the error, huh? #11922 You don't suppress error messages, you dumbass, you PAY ATTENTION and try to understand them. #11923 Never catch a signal except as a last resort. #11924 Well, if you don't know what it does, why did you put it in your program? #11925 Gosh, that wasn't very bright, was it? #11926 That's like taking a crap on someone's doorstep and then ringing the doorbell to ask for toilet paper. #11927 A good approach to that problem would be to hire a computer programmer. #11928 First get a book on programming. Then read it. Then write the program. #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way. #11930 Would you like to see my rate card? #11931 I think you are asking the wrong question here. #11932 Holy cow. #11933 Because it's a syntax error. #11934 Because this is Perl, not C. #11935 Because this is Perl, not Lisp. #11936 Because that's the way it is. #11937 Because. #11938 If you have `some weird error', the problem is probably with your frobnitzer. #11939 Because the computer cannot read your mind. Guess what? I cannot read your mind *either*. #11940 You said `It doesn't work'. The next violation will be punished by death. #11941 Of course it doesn't work! That's because you don't know what you are doing! #11942 Sure, but you have to have some understanding also. #11943 Ah yes, and you are the first person to have noticed this bug since 1987. Sure. #11944 Yes, that's what it's supposed to do when you say that. #11945 Well, what did you expect? #11946 Perhaps you have forgotten that this is an engineering discipline, not some sort of black magic. #11947 You know, this sort of thing is amenable to experimental observation. #11948 Perhaps your veeblefitzer is clogged. #11949 What happens when you try? #11950 Now you are just being superstitious. #11951 Your question has exceeded the system limit for pronouns in a single sentence. Please dereference and try again. #11952 In my experience that is a bad strategy, because the people who ask such questions are the ones who paste the answer into their program without understanding it and then complain that it `does not work'. #11953 Of course, this is a heuristic, which is a fancy way of saying that it doesn't work. #11954 If your function is written correctly, it will handle an empty array the same way as a nonempty array. #11955 When in doubt, use brute force. #11956 Well, it might be more intuitive that way, but it would also be useless. #11957 Show the code. #11958 The bug is in you, not in Perl. #11959 Cargo-cult. #11960 So you threw in some random punctuation for no particular reason, and then you didn't get the result you expected. Hmmmm. #11961 How should I know what is wrong when I haven't even seen the code? I am not clairvoyant. #11962 How should I know how to do what you want when you didn't say what you wanted to do? #11963 It's easy to get the *wrong* answer in O(1) time. #11964 I guess this just goes to show that you can lead a horse to water, but you can't make him drink it. #11999 You are a stupid asshole. Shut the fuck up.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python Django Conyes marineres
Connectant el blog amb Twitter
Escrit per Aaloy a 30 de December , 2009 a les 5:06 p.m.
Feia estona que volia connectar el blog amb Twitter, de manera que cada vegada que escrigui un post s'envii directament a Twitter sense tenir que fer-ho jo. No és gran cosa, però és la vagueria informàtica: si es pot automatitzar perquè fer-ho a mà? :)
De llibreries de connexió cap a Twitter des de Python n'hi ha un bon grapat, la majoria el que fan és crear un envolcall a l'API de Twitter per tal que sigui més manejable des de Python i evitar repeticions de codi.
La llibreria que jo he fet servir s'anomena twython i té el mèrit de ser la primera que he provat. Potser n'hi ha de millors o més completes, però pel que he de fer ja basta.
El que vull doncs és que cada vegada que escrigui un nou post, s'envii un nou Twitt. Per fer-ho hi havia dues opcions clares: sobrescriure el mètode save del model o bé utilitzar senyals.
He triat fer-ho amb senyals ja que m'estim més no fer massa complexe el mètode save, i a més la senyal post_save ja ens informa de si s'ha gravat un registre nou o un registre antic. El codi de fet és tan senzill com això:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # Signals def twitt_post(sender, **kwargs): is_new = kwargs.get('created') if settings.SEND_TWITT_ON_POST and is_new: instance = kwargs.get('instance') import twython try: twitter = twython.core.setup(username = settings.TWITTER_USER, password = settings.TWITTER_PASSWORD) twitter.updateStatus(_(u"Nou post al Blog de Trespams: %s %s") % (instance.headline, instance.get_absolute_url(), ) ) except AuthError, e: logging.error("Error in twitter account") logging.error(e.message) except Exception, e: loggin.error('Error in twitter post %s' % e.message) # Connect the signal with the callback post_save.connect(twitt_post, sender=Entry) |
twitt_post és el callback és a dir, la funció que es cridarà quan es gestioni la senyal, com a arguments passa la classe, la instància i si el registre es nou o no.
Obtenim primer si el post es nou o no, no vull empipar a la gent cada vegada que faci una correcció ortogràfica o tipogràfica, així que sols enviaré els twitts quan el post sigui nou. També he fet que sols s'envii si la variable de configuració SEND_TWITT_ON_POST així ho diu.
Després ja és cosa de utilitzar la llibreria (login i enviar, així de fàcil) i capturar les possibles excepcions.
Finalment el que feim és connectar l'event amb el model i la funció callback.
Si tot va bé aquest post ja s'hauria d'enviar automàticament.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python Django
I trobaré gent que sàpiga Python?
Escrit per Aaloy a 30 de December , 2009 a les 1:06 p.m.
Sovint quan plantejam que un desenvolupament ho farem amb Python i Django, la gent de les primeres coses que demana és a veure si trobarà gent que sàpiga Python i Django per dur el manteniment posterior, o si nosaltres deixam el negoci, o si ha de contractar algú, ...
Qui està un poc aficat en el tema de la programació web sap que és relativament senzill trobar gent de coneix PHP o Java, però encara el tema Python no està tan arrelat al subconscient com per a que soni com a llenguatge de referència.
Idependentment del que al final s'opti per un llenguatge o un altre, el "trobar gent" serà tant o més complicat en PHP o Java como ho pot ser en Python, ja que conèixer el llenguatge no implica necessàriament poder-se fer càrrec de l'aplicació o que el manteniment de la mateixa sigui senzill. És més, m'atreviria a dir que molts programes web que hi ha en PHP o Java són molt complexes de mantenir per algú aliè al desenvolupament inicial.
Aprendre un llenguatge és relativament senzill, conèixer-ne la sintaxi i poder llegir el codi pot dur pocs dies, setmanes si m'apurau. Després la tasca és saber com està fet el programa, entendre què fa i començar a trobar on s'ha de modificar cada cosa, i és aquí on el llenguatge importa menys que com s'ha desenvolupat el programa.
El model Python i Django fa molt més senzill fer programes bons de seguir, la sintaxi de Python es legible per pròpia construcció del llenguatge, i un programa que utilitzi Django com a bastiment i que segueixi les convencions de codi de Django mateix i de Python serà molt menys propens a les "sorpreses" que un típic programa PHP que segueix sols les convencions del seu programador, i segurament que a un programa Java-J2EE on vet a saber quines llibreries o tecnologia s'haurà utilitzat.
Amb això no vull dir que no es puguin fer programes mantenibles en PHP o Java, sinó que si el que volem en un futur és prendre el control del desenvolupament d'un programa que hem comanat a un tercer, el més important no és tant el llenguatge de programació sinó com estigui estructurat el programa, la legibilitat del codi, el comentaris i la documentació.
Quan un desenvolupament està fet en Python i Django augmentant les nostres possibilitats de que sigui mantenible posteriorment. Potser necessitarem un temps previ de formació en el llenguatge (o formar als nostres programadors interns), però aquest temps es veurà de sobres compensat per la facilitat de manteniment posterior. Per mi és una inversió de futur.
Traducciones/Translations by apertium
3 comentaris, 0 trackbacks (URL) , Tags: Python Django
Aquest 2009 s'acaba
Escrit per Aaloy a 20 de December , 2009 a les 1:38 p.m.
El 2009 ja gairebé s'ha acabat, així que com és habitual convé fer un poc de recapitulació del que ha estat l'any 2009 i definir el que esper del 2010.
Trespams
Sense haver acabat l'any aquest és l'apunt que fa 77, això vol dir que ha estat un any prou constant en el que és la publicació d'apunts en el blog, . M'agrada escriure, em relaxa i em permet posar idees en clar. Si a més aquests posts serveixen a algú més, encara que sols sigui per passar l'estona, crec que s'ho paga el petit esforç de posar-se davant l'ordinador i teclejar.
En aquest moments Trespams té uns 900 visitants més o manco habituals. D'aquest n'he pogut desvirtualtitzar un tant per cent molt petit, potser un 10%, alguns han deixat comentaris i hem pogut mantenir converses virtuals tant pel blog, correu o Twitter. Per mi és una de les experiències més gratificants del blog: poder compartir idees i pensaments amb comunicació bidireccional.
Des del principi el blog ha estat per mi essencial a l'hora de posar en ordre les meves idees i dèries. La gestió de projectes, la gestió d'equips de programació, l'estimació de projectes de programari, Python i Django. Tot sempre amb un fil conductor comú: el programari lliure.
El blog vol ser també part de la meva petita aportació al moviment del programari lliure. Programari lliure per mi significa no sols compartir codi, sinó compartir idees de com podem crear i gestionar aquest codi, eines, idees, ... El coneixement ha de fluir per a que tots com a societat ens en puguem beneficiar.
Python i Django
Per Python i Django també ha estat un bon any. Ha sortit l'esperada versió 3 de Python i Django ha assolit una velocitat de creuer que el consolida com un dels bastiments de referència en la programació web moderna. La llista de Django té uns 15.000 subscriptors, al repositori de projectes de Python, PyPi hi ha una cinquantena de projectes i actualitzacions de projectes diàriament.
Esper que el 2010 torni a ser un any Python, projectes com PyPy i Unladen Swallow poden donar encara més empenta a aquest fantàstic llenguatge. Esperem que l'onada Python arribi també a les empreses per a que tots ens puguem gaudir d'una programació més clara, mantenible i sobretot divertida, on el llenguatge no sigui un condicionant sinó un vehicle per a la creació de programes i la generació de valor per al negoci i en definitiva per a la societat.
Pel 2010 l'objectiu és anar creant més exemples a Appfusedjango, millorar-ne la documentació amb Sphinx. Voldria també millorar el codi d'aquest blog, fer-lo més accessible als dispositius mòbils. M'agradaria poder fer aportacions al projecte Basie, un projecte amb el qual he pogut coneixer noves formes de col·laboració, de control del codi, d'eines, nova gent.
Tot això farcit d'apunts en aquest blog, com a manera de presentar el que m'agrada, d'animar a la gent a participar, i com ja he dit, com a manera d'ordenar les meves pròpies idees. Es presenta doncs un any 2010 força interessant.
Creant Bits
Creant bits és la demostració del que es pot fer quan les idees es converteixen en accions. Un petit comentari al Twitter i la col·laboració de molta gent va fer possible que una vintena de persones ens trobàssim al Parc Bit per parlar de tecnologia, de Python i de Django.
La meva intenció és repetir-ho al llarg del 2010 i més si tenim disponibilitat de Sala. En aquests moments i baix el paraigües d'APSL tenim accés a les sales de formació del Parc Bit i convé aprofitar-ho. Quan no hi tenguem accés ja veurem que feim, però m'agradaria que fos quelcom que anàs perdurant en el temps fins que el cos aguanti i la gent no es cansi.
L'altra dia per un comentari que vaig fer al Twitter d'un curs de Python se'm va demanar si Creant Bits seguiria essent gratuït. La resposta es sí, Creant Bits és una aportació al moviment del programari lliure, com ho poden ser alguns dels apunts del blog, o altres projectes en els particip. No crec que es pugin considerar cursos en el sentit que l'objectiu del Creants Bits no és que la gent surti amb un coneixement profund de la tecnologia, sinó el de presentar el que es pot fer, parlar, reunir-nos i animar a la gent a provar coses, donant-los el primer impuls.
Els cursos sí que els cobr. Quan una empres em demana un curs de Python i Django els objectius és que la gent que participi surti amb un domini del temari que els faci ser productius una vegada acabat el curs. Són moltes hores de curs i moltes hores de preparació per la meva part. L'horari del curs, la localització i els assistents són responsabilitat de l'empresa que em contracta i és aquesta qui fitxa els objectius.
A Creant Bits ens reunim amics i coneguts, gent que ja ens coneixem de manera física i virtual o que tenim ganes de conèixer-nos, amb ganes d'aprendre coses i relacionar-nos. Potser al llarg del temps i amb diferents trobades la gent que participa es veurà amb un coneixements semblants als que tindria amb un curs formal, però això serà tant per l'impuls de la xerrada com per la seva iniciativa personal, i això crec que és la diferència fonamental amb un curs. A un curs vols que la gent surti preparada amb tants coneixements com sigui possible en un temps raonable, a una trobada com Creant Bit a mi el que m'agradaria és que la gent sortís amb motivació per poder començar, amb una petita llum a la foscor, que permeti, amb el seu esforça personal, avançar en el món del programari.
M'estic extenent molt amb aquest tros, però és que veure tanta gent reunida perquè sí per mi ha estat molt important, ja que ha representat passar del món de les idees al món de l'acció, del món de les intencions als fets. L'injecció de moral per mi (i esper que per als participants) ha estat grandiosa i tenc ganes de repetir l'experiència al 2010.
APSL
Al 2009 hem consolidat APSL, l'empresa de la que són CEO i soci. És una empresa atípica, feta a la nostra manera d'entendre els projectes, amb l'ètica al davant, sense voler tenir clients captius sinó essent-ne col·laboradors. Volem fer partíceps a les empreses del que significa el programari lliure, de com les coses es poden fer d'una altra manera fins i tot amb els pressuposts.
Estam intentant rompre amb la idea de pressuposts tancats per a projectes de programari. Creïem amb la idea de que el pressupost inicial ha de ser orientatiu, que després el que importa és que el programa que s'entregui representi el que necessiti l'empresa, que no és necessàriament el que l'empresa vol a l'inici del projecte.
No és una tasca senzilla, representa canviar un poc les regles del joc. Actualment les negociacions d'un projecte sempre estan encaminades a que el risc del projecte ho assumeixi una de les parts. El client intenta que sigui l'empesa desenvolupadora la que assumesqui el risc intentant tancar el mínim possible. L'empresa de programació intentant minimitzar el risc mirant de tancar-ho tot i de protegir-se en el pressupost. És una situació un tant perversa, en la qual tothom hi perd en un moment o l'altra, com en una ruleta russa.
Tot projecte té un risc i aquest hauria de ser compartit i minimitzat. Creim amb la idea d'Scrum com a metodologia de desenvolupament i com a manera de facturar a un projecte. El client assumeix un cert risc: el pagament anticipat d'una quantitat i l'empresa n'assumeix un altre: que l'empresa en qualsevol fita del projecte pugui tancar-lo, dient que el que té ja és el que volia o donar-lo a un altre proveïdor.
El 2010 m'agradaria que fos un any de creixement per APSL perquè voldria dir que aquesta filosofia de treball i gestió ha estat entesa, que una altra manera d'entendre la relació empresa-client és possible.
Gestió de projectes
A 2010 m'agradaria aprofundir en el tema de l'estimació de projectes des d'un punt de vista col·laboratiu. Una de les mancances que tenim com a col·lectiu és que estam massa encaixonats dins la nostra manera de veure les coses, potser sense tenir massa idea del mercat. Són les nostres estimacions raonables? Són les nostres maneres de pressupostar adients? Som competitius? Podem fer alguna cosa per millorar les nostres estimacions?
Crec que es un punt amb la cooperació hi té molt a dir. On podem col·laborar explicant projectes, explicant el perquè de les valoracions i el temps total, per a que serveixin de referència. També es podrien organitzar sessions d'estimació àgil, amb Planning poker estimation. És una idea a la que estic donant voltes però que encara no sé molt bé com organitzar.
També m'agradaria posar en marxa algun tipus de projecte col·laboratiu local, potser lligat al Creant Bits, que servesqui no sols per aprendre sinó també per tenir un producte que pugui beneficiar-nos a tots.
Moltes idees i molts projectes que m'agradaria fer. Tot això s'ha d'acompassar necessàriament amb la dedicació a la família, amb els projectes alimenticis i amb altres projectes que no estan lligats a la informàtica que m'agradaria assolir. Per exemple, no tenc cap coneixement de llenguatge musical, i és una cosa que des de fa anys m'agradaria aprendre. Potser el 2010 serà l'any...
L'any de la crisi
El 2009 passarà per ser l'any de la crisi, però tot i això crec que hem viscut temps interessants. El problema amb la famosa crisi és que tot s'ha enlentit, és com si haguéssim perdut un any, estant a l'expectativa, a veure-les venir. Per mi aquesta expectativa ha estat doble, ja que en hem trobat amb la fusió de TUIE i Hotelbeds, amb la qual cosa molts projectes s'ha paralitzat a l'espera del que passaria.
Com es diu "qui espera desespera", però crec que no ha estat el cas. La sensació de pèrdua de temps és intensa, però tot i això projectes com APSL, el Creant Bits, els passejos amb els nins amb bicicleta i els amics del Twitter no em queda la sensació d'any perdut, sinó d'any de reflexió, de tenir temps de descobrir coses noves i punts de vista diferents.
Encara que molts (la majoria) de pressuposts presentats encara estan al caixó d'algú, poder parlar amb els clients crec que m'ha enriquit com a persona, no des del punt de vista econòmic, però si des del punt de vista espiritual i tot suma!.
Com sempre un espera que l'any que començarà serà millor que l'anterior. Sigui com sigui serà també un any interessant de viure.
Traducciones/Translations by apertium
5 comentaris, 0 trackbacks (URL) , Tags: Informàtica Python Django Gestió de projectes Codi lliure APSL
Experiment amb Python i CAVAL
Escrit per Aaloy a 16 de December , 2009 a les 8:36 p.m.
Turistec ha presentat recentment la iniciativa CAVAL com una seria d'especificacions per promoure la interoperabilitat de dades entre solucions TIC per al sector turístic.
Aquestes especificacions tenen una implementació de referència a la web de proves de Viajes Urbis, on podem trobar la documentació, l'API de Java, els WSDL, els endpoints per REST i una plana de proves que ens permet testejar el nostre client contra l'especifiació d'Urbis.
Es d'agraïr l'especificació de referència d'Urbis, però la veritat, crec que estaria molt millor com a iniciativa de Caval i no deixar l'especificació de referència a una web separada del domini principal. Tal com està pareix com si s'hagués acabat la subvenció i no es pogués pagar el hosting o el desenvolupament. A més es podria posar el codi de la implementació a la web, donant la possibilitat de que la gent hi faci aportacions, encara que fos Caval l'entitat encarregada de certificar finalment la solució.
Ara és cosa de no deixar-ho morir, falta una implementació real de referència (podria ser la d'Urbis però amb la marca Caval), el codi font d'aquesta, poder tenir accés al codi des d'un control de versions i per què no poder participar amb aportacions i correcció d'errors. En la implementació de referència crec que es tindria que tenir en compte que la majoria de possibles consumidors de l'especificació són petites i mitjanes empreses. Això vol dir fugir d'implementacions de referència que requereixin grans instal·lacions o coneixements tècnics avançats, la implementació ha de tenir un nivell d'entrada molt suau, amb pocs requeriments de servidor, de tal manera que es pugui tocar molt ràpidament.
No sé si arribaré a fer una implementació de referència en Python, potser seria un bon exercici per futurs creant-bits, però el que sí es pot fer és començar a jugar amb el que té Urbis.
Per això farem servir Suds, com que estam de proves, en lloc de la llibreria recomanada farem servir la beta. Suds és una llibreria per a consumir serveis webs SOAP. A diferència d'altres eines com ZSI no genera codi, sinó que construeix els objectes al vol.
Anem per feina!
El primer que farem es descarregar la beta i instal·lar-la al nostre entorn. En el meu cas faré servir un virtualenv de manera que no tendré dependències amb altres paquets.
Com que volem veure les cridades que es generen establirem el nivell de login de Suds a DEBUG
1 2 3 4 | import logging logging.basicConfig(level=logging.INFO) logging.getLogger('suds.client').setLevel(logging.DEBUG) |
Per a fer les proves mapejarem el servei d'Hotels, que té per url http://test.viajesurbis.com/serveis/caval/20091127/soap/HotelBookingService?wsdl
1 2 3 4 | from suds.client import Client url = "http://test.viajesurbis.com/serveis/caval/20091127/soap/HotelBookingService?wsdl" client = Client(url) |
ara podem fer un print client per tenir l'estructura de mapeig que ha fet Suds,
Suds ( https://fedorahosted.org/suds/ ) version: 0.3.8 (beta)
build: R627-20091211
Service ( HotelBookingService ) tns="http://caval.travel/20091127/hotelBooking"
Prefixes (1)
ns0 = "http://caval.travel/20091127/hotelBooking"
Ports (1):
(HotelBookingServicePort)
Methods (6):
confirmHotelBooking(cavalHotelBookingConfirmRQ rq, )
getAvailableHotels(cavalHotelAvailabilityRQ rq, )
getDetailedValuation(cavalHotelBookingValuationRQ rq, )
getEstablishmentDataSheets(cavalGetEstablishmentDataSheetsRQ rq, )
getOffersList(cavalGetOffersListRQ arg0, )
notifyHotelBookings(cavalHotelBookingNotificationRQ arg0, )
Types (52):
abstractAuthenticatedAgencyRQ
abstractAuthenticatedRQ
abstractRS
...
roomOccupation
roomType
supplement
valuatedLine
valuatedOccupation
zoneWithOffers
Fitxau-vos que ens està donant els mètodes del web service i els tipus que hi ha definits.
Per tractar amb arguments simples no necessitam gaire cosa més. Podríem cridar als mètodes directament. El problema és que els arguments no són simples, així que tendrem que crear-los així com els necessitem.
Per a les nostres proves farem utilitzarem getAvailableHotels, com que a la web d'Urbis hi tenim un client web ens anirà bé per validar el que feim.
Cream l'objecte que contindrà la petició:
1 | rq = client.factory.create('cavalHotelAvailabilityRQ') |
si feim un dir(rq) podrem veure les propietats que té l'objecte
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | In [11]: dir(rq) Out[11]: ['__contains__', '__delattr__', '__doc__', '__getitem__', '__init__', '__iter__', '__keylist__', '__len__', '__metadata__', '__module__', '__printer__', '__repr__', '__setattr__', '__setitem__', '__str__', '__unicode__', 'agentId', 'airportIds', 'boardGroupFilter', 'checkIn', 'checkOut', 'cityIds', 'establishmentClassificationFilter', 'establishmentIds', 'establishmentNameFilter', 'excludeOnRequest', 'fromRow', 'gzipResponse', 'hotelCategoryGroupFilter', 'language', 'login', 'numRows', 'occupations', 'onlyOffers', 'password', 'removeHotelInfo', 'roomGroupFilter', 'rqId', 'stateIds'] |
Que podem comparar amb l'exemple de la web d'Urbis
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <?xml version="1.0" encoding="UTF-8"?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soapenv:Body> <getAvailableHotels xmlns="http://caval.travel/20091127/hotel"> <rq xmlns=""> <login>xml</login> <password>xml</password> <agentId>1</agentId> <language>es</language> <gzipResponse>false</gzipResponse> <stateIds>569061</stateIds> <checkIn>01/1/2010</checkIn> <checkOut>05/1/2010</checkOut> <occupations> <adultsPerRoom>2</adultsPerRoom> <childrenPerRoom>0</childrenPerRoom> <numberOfRooms>1</numberOfRooms> </occupations> <removeHotelInfo>false</removeHotelInfo> </rq> </getAvailableHotels> </soapenv:Body> </soapenv:Envelope> |
Però a més Suds ens dóna més informació damunt els paràmetres que el propi dir, així si feim un print rq
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | In [13]: print rq -------> print(rq) (cavalHotelAvailabilityRQ){ gzipResponse = None login = None password = None rqId = None agentId = None language = None airportIds[] = <empty> boardGroupFilter[] = <empty> checkIn = None checkOut = None cityIds[] = <empty> establishmentClassificationFilter[] = <empty> establishmentIds[] = <empty> establishmentNameFilter = None excludeOnRequest = None fromRow = None hotelCategoryGroupFilter[] = <empty> numRows = None occupations[] = <empty> onlyOffers = None removeHotelInfo = None roomGroupFilter[] = <empty> stateIds[] = <empty> } |
Podem veure que ens dóna també informació sobre els objectes i sobre els alguns d'ells són col·leccions, llistes Python.
Assignem-hi valors:
1 2 3 4 5 6 7 8 | rq.login = 'xml' rq.password = 'xml' rq.agentId = 1 rq.language = 'es' rq.gzipResponse='false' rq.stateIds=569061 rq.checkIn='01/01/2010' rq.checkOut='05/01/2010' |
Arribam ara a l'ocupació, aquí s'espera una llista del tipus availRQOccupation així que l'hem de crear l'objete primer
tal com he fet abans al la petició
1 2 3 4 5 6 | room = client.factory.create('availRQOccupation') room.adutlsPerRoom = 2 room.childrenPerRoom = 0 room.numberOfRooms = 1 rq.removeHotelInfo ='true' client.service.getAvailableHotels(rq) |
Si heu seguit els passos fins aquí veureu el log amb el SOAP-XML que s'ha generat, i que falla miserablement amb un error:
1 2 3 4 | <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body><soap:Fault><faultcode>soap:Client</faultcode> <faultstring>Unmarshalling Error: com/sun/xml/bind/v2/runtime/reflect/opt/Const </faultstring> </soap:Fault></soap:Body></soap:Envelope> |
Dont' panic!
Si comparam el que hem enviat (per això tenim el log a DEBUG) i ho comparam amb l'exemple que ens dóna Urbis veim que estam enviant tags buids i això a la implementació d'Urbis pareix que no li agrada gens.
Com que Suds fa la generació automàticament pareix que ho tenim un tant pelut, però no és així, supòs que Suds (si no ho ha fet ja) potser algun dia posarà l'opció de no generar tags buids, o potser la gent d'Urbis corregirà la implementació de referència per no petar amb aquests tags (que hauríen de ser vàlids, per una altra banda), però mentre és el que tenim, així que com a pas previ abans d'enviar-ho el que farem serà eliminar de la petició els atributs que estan buids.
1 2 | for attr in dir(rq): if not attr.startswith('_') and not getattr(rq, attr): delattr(rq,attr) |
si imprimirm el rq ara
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | (cavalHotelAvailabilityRQ){ gzipResponse = "false" login = "xml" password = "xml" agentId = 1 language = "es" checkIn = "01/01/2010" checkOut = "05/01/2010" occupations[] = (availRQOccupation){ adultsPerRoom = 2 childAges[] = <empty> childrenPerRoom = 0 numberOfRooms = 1 }, removeHotelInfo = "true" stateIds = 569061 } |
Si ara ho tornam a enviar veurem que torna a pegar una petada, però aquest cop si ens fixam ens retorna la resposta, la petada diu
ERROR: An unexpected error occurred while tokenizing input
The following traceback may be corrupted or invalid
The error message is: ('EOF in multi-line statement', (129, 0))
Als tips de Suds ens avisa que alguns servidor posen caràcters de control a la responsta que fan que el parsejador SAX que fa servir Suds doni una excepció (ara ja sabeu perquè la gent fa una rialla d'aquelles d'incredulitat quan li dus que la S de SOAP ve de Simple), per això el permet Suds és afegir-hi un filtre a la resposta
1 2 3 | import string from suds.bindings.binding import Binding Binding.replyfilter = (lambda s,r: ''.join([c for c in r if c in string.printable])) |
Ara sí:
1 2 | rs = client.service.getAvailableHotels(rq) print rs.totalRows |
En el meu cas m'han sortit 76 hotels. Si feim un print rs en veurem l'estructura de dades, i amb un dir(rs) les propietats i mètodes que tenim disponibles, ens fixam amb availableEstablishments
A partir d'aquí ja és sols cosa d'anar accedint als distints elements de l'estructura i decidir com presentam la informació que hem obtingut. Per exemple i per no fer-me massa llarg, per imprimir els noms dels hotels que hem trobat basta fer:
for hotel in rs.availableEstablishments:
print hotel.establishmentName
Per acabar, si us demanau pel rendiment d'això, heu de saber que Suds manté el WSDL en caché, de manera que no necessita demanar-lo cada vegada. La caché és configurable.
Pel nostre exemple, la disponibilitat de la tenim en poc més de 3 segons.
2009-12-16 20:07:36,179-INFO-__main__-36-Iniciam la consulta 2009-12-16 20:07:39,215-INFO-__main__-38-Fi de la consulta
Considerant que en el entorn de test via web d'URBIS la resposta l'obtenim entre 10 i 14 segons, doncs jo dira que està d'allò més bé.
Pos tot el codi per a que sigui més fàcil fer les proves:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | #!/usr/bin/env python # -*- coding: UTF-8 -*- import logging logging.basicConfig(level=logging.INFO, format="%(asctime)s-%(levelname)s-%(name)s-%(lineno)s-%(message)s",) logging.getLogger('suds.client').setLevel(logging.INFO) log = logging.getLogger(__name__) from suds.client import Client import string from suds.bindings.binding import Binding # Com que la resposta té problemes filtram Binding.replyfilter = (lambda s,r: ''.join([c for c in r if c in string.printable])) url = "http://test.viajesurbis.com/serveis/caval/20091127/soap/HotelBookingService?wsdl" client = Client(url) rq = client.factory.create('cavalHotelAvailabilityRQ') rq.login = 'xml' rq.password = 'xml' rq.agentId = 1 rq.language = 'es' rq.gzipResponse='false' rq.stateIds=569061 rq.checkIn='01/01/2010' rq.checkOut='05/01/2010' room = client.factory.create('availRQOccupation') room.adultsPerRoom = 2 room.childrenPerRoom = 0 room.numberOfRooms = 1 rq.occupations = (room, ) rq.removeHotelInfo ='true' # no volem informació de l'hotel ara # bug? de la implementació de referencia, eliminam tags buids. for attr in dir(rq): if not attr.startswith('_'): if not getattr(rq, attr): delattr(rq,attr) log.info('Iniciam la consulta') rs = client.service.getAvailableHotels(rq) log.info('Fi de la consulta') # i la llista d'hotels for hotel in rs.availableEstablishments: print hotel.establishmentName |
Traducciones/Translations by apertium
3 comentaris, 0 trackbacks (URL) , Tags: Python
Creant bits amb Django i Python
Escrit per Aaloy a 04 de December , 2009 a les 11:46 p.m.
Hem arribat a la sala als voltants de les 14:30, allà el responsable tècnic del Parc Bit (Gillem) ens ha explicat com estava tot, endollat el projector i ajudat amb les cadires. Un 10 per la gent del Parc Bit i de l'Incubit, tant per deixar-nos la sala com per l'ajuda.
Hem començat a preparar-ho tot. Respiram un poc més tranquils quan hem comprovat que la connexió a Internet funcionava. Després de 2 mesos i busques sense ADSL començava a pensar que teníem gafe.
Als projectors no els sol agradar el portàtil amb resolució de 1920px, així que m'ha toca configurar-ho un poc. El projector una passada, arriba a 1600x1200 px i des del fons de la sala es veu bé.
La sala de formació té capacitat per unes vint i tantes persones assegudes a la taula. No hi havia cadires abastament i la gent del Parc Bit ens ha ajudat a torbar-ne més.
Després d'això, quan al part tècnica ja funcionava hem anat a cercar la poca intendència que hi ha preparada: aigua i gominolas. Si tot falla, pens, al manco la gent que vengui se'n podrà anar amb un gust dolç.
Primera sorpresa del dia: Xus s'entrega amb una cafetera Nesspresso, cafè i galletes per tothom. No tenc paraules!
Son les 15:30, ja ho tenim tot llest i anam a fer una mossegada ràpida. Allà trobam gent coneguda que també assistiran a la trobada.
En Juan s'adelanta per anar rebent la gent, seguidament baixam, són les quatre i comença a omplir-se la sala.
Molta gent coneguda, amics virtuals que es desvirtualitzen. Em sap greu poder dedicar més temps a presentar-nos com toca, esper que hi haurà més ocasions.
A les 16:30 aproximadament començam: primer amb la part Python i després amb Django. L'objectiu és evitar la por a començar, donar la primera empenta. Qued admirat pel nivell que hi ha a la sala. Veure tants informàtics junts, interessats per aprendre em fa tornar l'esperança en la professió. Sols per això ja s'ho paga els nirvis de muntar una cosa d'aquestes.
No sé estar assegut, m'agrada més explicar i comentar passejant, les gominolas al manco ajuden a recuperar energies. El michelín ho notarà segur :)
Hem acabat amb més de mitja hora de retràs de la part Django, En Bernat tendrà menys temps. És una llàstima, perquè una de les gràcies de Django és la flexibilitat que té per a deplegar-se allà on més ens convengui a nosaltres. Ha de resumir molt la xarl·la i es limita a mostrar la configuració amb mod_python. A veure si a la propera ens dona temps de que mostri wsgi i la potència del balanceig.
Són les nou passades. Acabam. Anam saludant a la gent que marxa i començam a recollir. Encara queda temps per anar parlant amb la gent que queda de batalletes i tecnologia.
En Pau i na Sílvia han fet fotos, quan les tengui les penjaré junt amb les presentacions. Els twitts estan com creant_bits.
Fi de la crònica!
Gràcies a tots per assistir, perdonau els que no heu pogut venir per falta d'espai. La gent que ha vingut de ben segur que us contarà que la sala tampoc no donava per massa més. Però no serà la darrera!
Moltes gràcies a Juan (morenosan), Xus (m'has deixat sense paraules) i Pau per les labors d'assistència tècnica. Gràcies especialment per Bernat, que s'ha currat una presentació. A Paco per la idea del nom, i per damunt de tot a tota la gent que un divendres de pont s'ha desplaçat al Parc Bit i ha estat més de cinc hores compartint la nostra passió per la informàtica.
Si algú em diu que a partir d'una twittejada es podia muntar un sarau com aquest no m'ho crec. La màgia de la comunicació!
Com dic, esper que no sigui la darrera. Personalment he gaudit del contacte amb els assistents, de desvirtualitzar gent, de veure que la visió que tenc de la informàtica és compartida, de pensar que les coses es poden fer d'una altra manera.
Avui no dormiré! :)
--
He pujat les presentacions a SlideShare. Les fotografies són a Flicker, gràcies a Silvia i Pau.
Traducciones/Translations by apertium
8 comentaris, 0 trackbacks (URL) , Tags: Python Django
Desplegament de Django
Escrit per Aaloy a 29 de November , 2009 a les 1:53 a.m.
Una de les característiques que més m'agraden de Django per desenvolupar és que ja ve amb el seu propi servidor integrat. És un servidor no apte per entorns de producció, de fet a les planes de Django es recomana repetides vegades que NO es faci servir a producció, però que va molt bé al desenvolupament.
El que fa tenir aquest servidor és per una banda acursar el temps necessari per començar a desenvolupar. Una vegada creat el projecte i la primera aplicació, posam el servidor en marxa amb un python manage.py runserver i ja tenim accés a un complet servidor web.
A més ens permet depurar des del principi les nostres aplicacions. La consola del servidor que acabam d'executar mostrarà els missatges del servidor i els logs que li enviem com un servidor web qualsevol, però a més ens servirà de consola de depuració de Python.
Encara que hi ha entorns com Eclipse+Pydev que ens permeten posar punts de ruptura directament al codi, un dels mètodes més simples consisteix en escriure import pdb;pdb.set_trace() allà on vulguem que s'aturi el programa. Llavors, en arribar-hi a la consola on hem executat el servidor ens apareixerà l'entorn de depuració de Python (el pdb). Si volem fer un poc més de feina podem instal·lar l'ipdb i tendrem una consola de depuració amb autocompletat i resaltat de sintaxi.
A Python diuen allò de "batteries included" per indicar que amb Python hi ha tot el necessari per arrancar, Django segueix la mateixa filosofia, de manera que no necessitam configurar cap servidor web per començar a fer-hi feina i ens proporciona a més eines de depuració prou potents: la possibilitat de depurar amb pdb/ipdb o semblants, la depuració mitjançant els missatges d'error de les plantilles o la possiblitat de depurar evitantn la recàrrega amb l'opció de --no-reload del servidor de desenvolupament.
Una vegada ja tenim l'aplicació creada i depurada passam al desplegament. Pels experts de sistemes no ha de ser cap problema seguir les instruccions de les instruccions de desplegament de Django. Es pot desplegar en Apache (mod_python o mod_wsgi), damunt ngnix, lighthttp, Cherokee, ... En general no es tant cosa del servidor com de triar una tecnologia considerant el nostre entorn d'execució.
Perquè pensau que Django està pensat per ser escalable per amunt i per avall. Segons les restriccions del nostre entorn de producció ens convindrà elegir una tecnologia o una altra. Decidir si ens convé tenir un sols servidor http o separam l'execució de l'aplicació del servidor de continguts, quin tipus de caché farem servir, etc. etc.
Tot és molt flexible, però aquesta flexibilitat fa que ens tenguem que fer preguntes, Django no decideix per nosaltres com s'ha d'instal·lar. Fa recomanacions però en general s'adapta al que hi ha.
Si un disposa d'uns tècnics de sistemes com els que jo tenc la sort de fer feina, aquesta flexibilitat és fantàstica, segons l'aplicació decideixen la tecnologia que es fa servir, la caché, les instàncies que s'aixecaran o com es serveix el contingut estàtic. Si un s'ho ha de fer tot i no disposa d'un servidor propi (o al manco d'un servidor virtual) el desplegament vindrà marcat pel que ens deixi el nostre ISP.
Posar una configuració? Doncs no, dependrà de cada aplicació i de cada entorn. Sols un parell de recomanacions:
- wsgi funciona molt bé
- Si podeu separau el servidor d'aplicacions Django del servidor de contingut estàtic.
- Amb un poc més de pressupost es pot tenir un servidor dedicat o virtual configurat i podrem treure tot el suc a la nostra aplicació.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python Django
Una ullada a Sphinx
Escrit per Aaloy a 27 de November , 2009 a les 11:36 p.m.
Si heu fet servir la documentació de Python, Django o potser alguna de les aplicacions més importants o darrerament li heu fet una ullada al Building Skills with Python us n'adonareu que comparteixen un estil comú. Django ha personalitzat les plantilles, però com podem veure a la part on explica com es crea i es contribueix a la documentació, podem feure que Django fa servir Sphinx.
Sphinx és l'eina amb la qual s'estan creant les documentacions dels principals projectes basats en Python (encara que ens permet escriure qualsevol tipus de documentació) i poc a poc esdevé la killer appplication de la documentació tècnica.
Començar amb Sphinx és prou senzill, sols necessitam tenir Python instal·lat i
$ easy_install Sphinx $ sphinx-quickstart
i anar contestant les preguntes. Si heu compilat alguna vegada algun programa al món Unix veureu com quan acabin les preguntes s''haurà creat un directori amb un arxiu anomenat Makefile (make.bat per altres). Executant-lo ens crearà un directori build amb les bases del que pot ser la nostra documentació.
I és que Sphinx és bàsicament un compilador orientat a la creació de documentació. Agafa documents escrits en Restructured Text i crea un lloc web en HTML, genera un pdf o latex. Això vol dir que per poder treure'n el màxim partit s'ha de conèixer Restructured Text i fer-li una ullada a les comandes que Sphinx incorpora per crear les taules de contingut, fer el resaltat de sintaxi, incorporar imatges o fórmules matemàtiques. Una vegada passat el període d'aprenentatge (que ja us dic que és curt) veureu que el resultats que s'obtenen són espectaculars.
Ja he dit sovint pel blog que m'agrada escriure la documentació (i escriure en general) en text pla, utilitzant LaTeX, Markdown o ResTructured Text. Sphinx ajunta el fet de poder escriure la documentació com m'agrada amb un resultats realment professionals. És a la documentació hipertextual el que LaTeX és per a la documentació científica.
Potser ara us estareu demanant perquè fer la documentació amb aquesta eina i no limitar-nos a un document amb OpenOffice (o fins i tot en Word!!!), se m'acudeixen un parell mallorquí de raons:
- El text pla es pot posar damunt un control de versions.
- Permet que molta gent participi en la creació de la documentació.
- Sphinx ens dóna unes plantilles que fan que la documentació llueixi.
- El ressaltat de sintaxi Python ve de sèrie i costa ben poc fer el ressaltat per altres llenguatges.
- El cercador està inclòs a la documentació
Però sobretot, perquè amb Sphinx escriure documentació és divertit. Pots distribuir-te la feina com vols, no has de passar ànsia per la maquetació final, ni per que les imatges se t'han descol·locat i no saps on han anat a parar (si heu fet documents de més de 20 planes amb un processador de text sabreu què vull dir). I que escriure documentació no sigui feixuc segurament farà que ens faci menys peresa documentar i tothom ens estarà eternament agraït. Jo ja he començat amb la documentació d'appfusedjango que no se digui que no predic amb l'exemple.
Personalment crec que Django ha marcat un abans i un després en el món de la documentació de projectes, de tal manera que cada dia més projectes i aplicacions emulen la manera de documentar de Django i Django (com Python) fa servir Sphinx. Demostrant que per a que un projecte tengui èxit no basta que sigui bo sinó que ha d'estar ben documentat.
No cerquem en Sphinx la bala de plata. Fer bona documentació no és senzill, Sphinx sols fa que sigui menys pesat i ens dóna un resultat final molt més amigable als nostres lectors. Un dels creadors de Django,Jacob Kaplan-Moss, ha escrit un conjunt de posts damunt com s'ha d'escriure bona documentació: Writing great documentation, de lectura imprescindible. Però tot i que no sigui fàcil s'ha de començar, ens hem d'avesar (i jo el primer) a que Sphinx sigui part de les eines de projecte, a escriure documentació i a millorar el nostre estil, tanmateix diuen que la pràctica fa el mestre, no?
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python Django
Ulipad 4
Escrit per Aaloy a 24 de November , 2009 a les 11:53 p.m.
Acab de devallar-me la darrera versió (la quatre) de l'editor Ulipad. És un editor fet en Python damunt les llibreries wxPython.
La primera impressió que m'ha donat l'editor es pot resumir en una paraula: velocitat. És un editor molt ràpid, carrega en pots segons i l'autocompletat de codi, a més d'estar a un nivell molt bo, és també molt ràpida. Sols per això ja trob una justificació més que raonable per donar-li una oportunitat.
La gestió de projectes és un tant limitada, únicament ens presenta un sistema de fitxers, però és suficient per la majoria de projectes.
El suport de Python és molt bo i és extensible mitjançant plugins. En té un per Django que ens deixa executar el servidor de desenvolupament de Django. Tanmateix tot això és un poc anecdòtic si ho comparam amb la senzillesa i usabilitat d'aquest editor. Per ara (i duc una hora llarga amb ell) m'està agradant molt.
Destacar la bona integració que té amb la shell de Python, basant-se en pyCrust, la integració amb pylint i un parell d'utilitats que ens fan la vida més fàcil: un testejador d'expressions regulars i un gestor de trossos de codi (snippets).
Una altra de les coses que m'ha agradat és el suport que té per a l'edició de documents en RestructuredText, permetent-nos tenir una previsualització en temps reals de com queda el document.
He trobat a faltar un major suport per l'execució de test unitaris (sols té integrats els doctests) i la integració plena d'un depurador. Es recolza en un depurador molt bo, en Winpdb, però en aquesta versió pareix que s'ha deixat un tant desactualitzat. Supòs que obrint un ticket s'arreglarà aviat.
És un editor senzill, útil per que vol un editor gràfic i no pot o vol fer servir IDEs com Netbeans o Eclipse.
Traducciones/Translations by apertium
3 comentaris, 0 trackbacks (URL) , Tags: Python Django
Anunci Python i Django workshow
Escrit per Aaloy a 20 de November , 2009 a les 8:24 p.m.
Actualització
Hem arribat als 20. La resta haureu d'esperar a la propera!
Tothom que s'ha apuntat fins al meu darrer comentari, el 24 entra dins aquest primer workshow. Aniré posant per aquí i pel Twitter les novetat que hi hagi.
Em sap greu pels que els agradaria venir i han quedat fora, però compreneu que la sala és petita, 20 persones són moltes i el format que hem pensat (amb voluntaris ajudant als nouvinguts) no dóna per massa més.
Si la cosa agrada us promet que no serà la darrera! :)
No sé quin nom posar-li, en Paco proposa al twitter "programming python & django before beers" o "def bit():" però a les hores que acabarem (més de les 18:00) ja us dic jo que al Parc Bit no hi ha res obert per anar fer unes cerveses. M'ha agradat molt el Creant Bits, començant amb Python i Django i ja veurem com acabarem...
Així doncs faig l'anunci oficial:
Creant Bits amb Python i Django Divendres 4 de desembre Hora: 16:00 a 20:15 (o més) Lloc: Sala de formació del Parc Bit Organitza: APSL Col·labora: Incubit, que ens deixa la sala.
En quant als continguts, crec que els hauríem d'afinar entre tots. Per començar jo us proposaria el següent:
- Introducció a Python (1.5h)
- Pausa (15 min)
- Introducció a Django (1.5 h)
- Pausa (15 min)
- Posant una aplicació Django a producció (45 min)
La idea seria que la gent li fa ganes saber què és això de Django i Python pugui fer-se'n una idea. Es donarien quatre pinzellades de Python, amb exemples que tothom pugui executar al seu portàtil.
Per la part Django: mostrar com començar, que és, veure com es pot crear una plantilla, l'organització del codi i veure alguns exemples d'aplicacions, etc. Ha de servir com a presa de contacte i que tothom pugui fer-se una idea de les possibilitats que té aquest bastiment.
Com que al final el que volem tots és posar-lo en producció, s'explicaria com n'és de bo de fer posar-ho a un entorn Apache.
Però com us dic sols és una idea. El temps és limitat, però si estau interessats en donar-li una altra orientació estic obert a qualsevol possibilitats.
Requisits
- Tothom amb el seu portàtil, millor amb Linux. Si algú vol dur el seu fix i pantalla serà benvingut, però avís que hi ha una passejada i no sé com està la sala d'endolls.
- Python 2.5 ó 2.6 instal·lat, el 3.x no us funcionarà amb Django.
- Un editor amb ressaltat Python: vim, gvim, notepad++, Netbeans, Eclipse, ...
- La darrera versió estable de Django insta·lada. La 1.1.1 en el moment d'escriure això.
- Navegador Firefox amb el Firebug instal·lat
- iPython instal·lat
Inscripció
Lliure, però teniu en compte que la sala té una capacitat d'unes 20 persones, així que, per favor, deixau un comentari per a que pugui controlar quants serem i saber si hem arribat al límit de la sala. Al comentari podeu posar el tipus d'orientació que us agradaria.
Quan serà la propera?
Dependrà de l'èxit d'aquesta i de que Parc Bit/Incubit tengui lliure la sala i ens la cedesqui (des d'aquí moltes gràcies des de ja!). M'agradaria que això acabàs com a grup d'usuaris/empreses més o manco estable, però això ho hem de decidir entre tots.
Altres
Miraré d'informar-me com està la sala en el tema de connexions d'Internet. Si hi ha connectivitat fins i tot podríem intentar fer un projecte en grup, si no aquesta potser la propera vegada.
M'agradaria poder dir que hi haurà catering, però seria mentida :)
Traducciones/Translations by apertium
33 comentaris, 0 trackbacks (URL) , Tags: Python Django
Planes estàtiques amb Flatpages
Escrit per Aaloy a 19 de November , 2009 a les 6:15 p.m.
Fa estona que volia posar contingut no directament relacionat amb el Blog a Trespams, ja sabeu, quí soc, sobre el blog i coses d'aquests, però no ho arribava a fer. Finalment m'he decidit i aprofitaré per explicar com podem fer aquest tipus de coses amb Django.
El primer de tot és centrar el problema. L'objectiu és tenir lligat a la nostra aplicació (el blog en aquest cas) un conjunt de planes que no estan relacionades amb l'aplicació o aplicacions, que no han de ser editades o ho han de ser molt poc.
El cas típic són les planes de condicions legals, les planes de "sobre mi" dels blogs. Agafau la idea, no?
Com que és un cas molt comú Django té una aplicació al contrib pensada per fer precisament això. Ens proporciona un formulari on podem posar el títol, el contingut en format html i indicar si volem la plantilla que s'utilitzarà, si permetem comentaris o no i si l'usuari ha d'estar registrat al sistema per veure la plana. Aquesta aplicació se'n diu Flatpages.
La documentació de Django està força ben explicada.
-
Afegim 'django.contrib.sites' a INSTALLED_APPS del nostre setting.py si no hi és ja. Si no hi era convé fer un syncdb. Crearem una entrada al Sites amb la nostra url i també posarem el SITE_ID del settings.py el valor de l'id d'aquest registre. Si sols en teniu un serà 1.
-
Afegim 'django.contrib.flatpages' als INSTALLED_APPS.
-
Afegim 'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware' a MIDDLEWARE_CLASSES del settings.
-
Executam
python manage.py syncdbper a generar les taules de Flatpages. -
Cream el directori flatpages dins el nostre directori de templates i cream l'arxiu d'default.html. Aquesta serà la plantilla per defecte que s'utilitzarà. Hem de personalitzar-la com volguem. A aquesta plantilla flatpages li passa la variable
flatpage, a partir de la qual podem obenir el títol i el cos del text amb{{flapage.title}}i{{flatpage.content}}. Podeu fer una ullada al codi de trespams del svn per tenir-ho més clar.
Ara ja sols és cosa d'anar afegint registres amb les urls i continguts que volguem. Django en no trobar una plana abans de mollar un 404 el que farà és anar a flatpages, si la url correspon a una que hagem definit generarà la plana a partir de la plantilla i els continguts del registre corresponent.
Per acabar, dir que no fa falta posar el filtre safe a les variables. Per defecte se suposa que l'html és segur, ja que no està pensat per a que un usuari extern a l'aplicació l'editi.
Traducciones/Translations by apertium
2 comentaris, 0 trackbacks (URL) , Tags: Python Django
Comparant Django i Drupal
Escrit per Aaloy a 16 de November , 2009 a les 5:56 p.m.
Pareix que alguns desenvolupadors de PHP s'estan plantejant anar cap a Python i Django com a una via per a fugir de les complexitats i problemes del PHP.
Des d'aquest blog vull encoratjar-los a al manco provar-ho i després decidir si convé o no fer l'esforç. Personalment pens que sí, pero tot dependrà de l'experiència que tengui cada un i de com vulgui enfocar els projectes.
Per ajudar en la decisió trob que és força interessant visitar dos enllaços:
El primer és una apunt i el segon és la discusió a un fil de la llista d'usuaris de Django. No us perdeu els comentaris, on es discuteix si Django i Drupal són comparables o no.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python Django
Python Essential Reference - 4th Edition
Escrit per Aaloy a 02 de November , 2009 a les 11:14 a.m.
Python Essential Reference, en la seva quarta edició és un llibre dens, com es pot esperar d'un manual de referència, així que no és el millor llibre per a introduir-se en la programació amb Python, en canvi, si ja heu seguit algun tutorial, o algun altre llibre introductori, trobareu que Python Essential Reference toca aspectes pocs coneguts del llenguatge.
El llibre està dividit en tres parts, la primera, més de 200 planes, tracta la sintaxi del llenguatge en profunditat, la segona part, la referència en sí, va desgranant les principals llibreries que hom pot trobar de sèrie en una distribució de Python i la tercera ens ensenya com extendre Python amb C i com es comunica Python amb altres llenguatges (C, .Net o Java).
No es pot dir que ell llibre tengui caràcter pedagògic, però els exemples són als punts justs on ajuden a fer-se una bona idea del que se'ns explica. Com que l'autor David M. Beazley també contribueix a la documentació de Python trobarem que hi ha força semblances entre la documentació oficial i aquesta referència, tot i això, la manera d'explicar algunes coses i l'organització de la documentació és diferent i fa que se n'aprofiti més la lectura.
És un llibre per tenir aprop quan un programa en Python i per rellegir de tant en tant, a l'era Internet aquets tipus de manuals en paper són cada cop menys necessaris, però tot i això útils per gent com jo que prefereix llegir amb comoditat i/o en qualsevol lloc o moment.
Fitxa tècnica:
Python Essential Reference 4th Editon David. M. Beazley Ed. Addison Wesley ISBN: 978-0-672-32978-4
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Llibres i revistes Python
Mantenibilitat en llenguatges tipats i no tipats
Escrit per Aaloy a 01 de November , 2009 a les 12:38 p.m.
Quan surt aquesta discusió sovint, al manco al meu àmbit, la discusió es redueix a comparar Java i Python. Recentment en Paco ha obert la capsa dels trons al twitter amb una afirmació "Para escribir código mantenible, mejor un L.P. fuertemente tipado. Si es compilado, mejor".
Damunt el tipat o no em remetré al post de Ned Batchelder i a un comentari d'aquest post, amb al qual hi estic d'acord en un 90%, que traduït lliurement i sense limitar-ho a java diria:
-
Python maximitza la productivitat dels bons programadors
-
Els llenguatges tipats (Java a l'original) minimitzen el mal que els programadors mediocres poden fer al sistema.
Tant de bo la segona afirmació fos certa. La gent pot ser molt creativa i cap tipat del món no pot evitar que es faci un borrat complet contra la base de dades, que s'equivoqui amb l'algorisme del càlcul de l'IVA, les possibilitats són infinites. La referència obligada de que el tipat fort no és cap garantia de mantenibilitat la tenim al post How to Write Unmaintainable Code o passar-se per The daily WTF. El primer cas és fins i tot més sagnant, ja que la gran majoria d'exemples i tècniques es refereixen a llenguatges fortament tipats com el C, C++ i Java. Usos creatius del define, noms de variables que no tenen res a veure amb el que fa la variable, noms lleugerament semblants que fan coses totalment distintes,...
No vull fer sang damunt el tipat fort, la majoria de les coses que expliquen al How to Write es poden extrapolar a qualsevol llenguatge de programació. Però la realitat és el tipat fort no és cap garantia de mantenibilitat.
La mantenibiliat ens la donen les convencions del codi, la documentació, la inspecció periòdica o sistemàtica del nostre codi (o del codi d'altres), el llegir el code complete i aplicar els consells i pràctiques també ajuda força. Tenir test unitaris, programes que ens gestionin l'adherència als estàndarts i la complexitat del codi (n'hi ha per Java, Python, C++, ...), gestió acurada del errors, tests de regressió, etc. a l'hora de la mantenibilitat poden fer molt més que el simple tipat.
Potser perquè molts de programes que he fet al llarg del temps s'han mantingut en producció durant anys sóc un tant fanàtic de la mantenibilitat, preferesc codi matenible a codi guais que al cap d'un mes ningú, ni el seu creador, sabrà perquè ho va fer d'aquella manera. I aquest tipus de mantenibilidad no la dóna el tipat fort o el compilador, la mantenibilitat ens la dóna la gent i les regles que ens imposem a l'hora de crear el codi.
Com la seguretat la mantenibilitat no és quelcom que es pugui posar una vegada el programa està llest. La mantenibilitat ha de formar part del procés de desenvolupament. Sovint he refet o he fet refer codi perquè era mal de seguir, per massa acoblament, perquè la quantitat de ifs feia difícil saber per on anava el codi, i això m'ha passat tant en Java, Pascal o FORTRAN com en Python.
Llavors, pensant en que els programes es fan per a ser mantenibles tant en llenguatges tipats com en els no tipats, la pregunta que ens faríem doncs és perquè triar un llenguatge o un altra i aquí ja entraríem en un altre tipus de discusió.
Si pensam sols en termes de mantenibilitat i suposant que programam com toca potser estarem d'acord que hauríem de triar un llenguatge que fos bo de llegir, de seguir, expressiu i d'alt nivell. El millor codi és aquell que no s'ha d'escriure.
Per mi pocs llenguatges compleixen això tant bé com Python, és un llenguatge molt clar de llegir, amb una corba d'aprenentatge molt suau i amb una dèria cap a la llegibilitat i la mantenibilitat que està incorporada al llenguatge dins la pròpia sintaxi (la identació) i a l'intèrpret mateix (provau import this) o llegiu The Zend of Python i les convencions de codi són públiques i definides des del 2001, la qual cosa no vol dir que no s'hagin canviat al llarg del temps.
En conclusió: el codi mantenible no ho dóna un compilador sinó el programador i la gestió que se dugui del projecte. No podem confiar en que el tipat fort ens farà la feina i ens alliberarà de la feina de crear tests unitaris, de comprovar que el codi està d'acord als estàndards o de que fa el que ha de fer.
Java, C, C++ són grans llenguatges no perquè tenguin tipat fort, sinó pel que els programadors hem fet amb ells. De la mateixa manera Python, PHP, Perl, Ruby són grans llenguatges no per la seva absència de tipat, sinó per codi que ens permeten escriure.
Traducciones/Translations by apertium
4 comentaris, 0 trackbacks (URL) , Tags: Informàtica Python Java Gestió de projectes
Curs de ASCII art en Python - I
Escrit per Aaloy a 25 de October , 2009 a les 4:25 p.m.
Avui iniciam el primer curs de ASCII art en Python. Per començar un repte: el pare de n'ETE en ASCII art, generat en Python. Seria així:
1 | print(chr(79)) |
I ja ho tenim, Don ETE!
Eps! Algú ha vist les meves pastilles?
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python Conyes marineres
Risc o seny
Escrit per Aaloy a 25 de October , 2009 a les 8:56 a.m.
Llegint l'article de Ned Batchelder, "The Scalability of programming languages" me n'adono que es troba en una tesitura com la que jo potser me trobaré d'aquí poc. Ell, un dels creadors de Tablo, comprat fa dos anys i mig per HP, es veu que es troba sota pressions per deixar de desenvolupar l'aplicació en Python per fer-ho en un dels llenguatges "corporatius" d'HP.
Per mi Django i Python representen un avantatge competitiu, ja que permeten una posada en producció, des de la concepció de la idea fins a posar l'aplicació al servidor, molt més curta, un temps de reacció als canvis i incidències difícilment superable, i sobretot, una capacitat de manteniment que fa que es pugui tocar una aplicació feta fa anys sense problemes.
El més curiós,però, és veure com les novetats, tot allò que pot representar una ruptura amb "la manera de fer les coses" presenta un problema fins i tot en les empreses que han fet de la innovació una de les seves raons de ser.
En una era on la tecnologia representa un avantatge competitiu important, limitar-se a allò que fa tot hom vol dir que no s'aprofita aquest avantatge. Això no vol dir tirar-se de cap cap a una nova tecnologia tan aviat com apareix, però una vegada avaluada, si la nova tecnologia representa una millora respecte al que tenim, el risc de ser dels primers en fer-la nostra es pot veure compensat per l'avantatge que ens donarà. Fins i tot si es demostra que la tecnologia no era allò que esperàvem, l'esforç necessari per a implantar-la i el canvi mental que suposa, farà que el nostre equip estigui més obert a les novetats i que llavors sigui molt més senzill anar introduint millores als nostres processos.
És un poc també com la situació en la que una empresa té l'opció de crear un nou programa per a comercialitzar els seus productes o comprar-ne un de ja fet. Desenvolupar-lo implica més risc i cost, però ens dóna un control total damunt el programa i podem fer-hi les modificacions que facin falta per adaptar-lo als nostres processos de negoci. Comprar-ho fet vol dir que qualsevol amb el capital suficient pot fer el mateix que nosaltres comprant el mateix programa que nosaltres. El que es dóna a més, és que nosaltres podem haver pagat per unes modificacions al programa que han costat temps i esforç de desenvolupar, i la nostra competència les tendrà des del primer dia a cost zero. Adéu a l'avantatge competitiu!
En aquests moments la tecnologia web i els llenguatges que li donen suport estan en un moment d'evolució important: llenguatges d'script per desenvolupar webs, pas cap a models de base de dades no relacionals, utilització de bastiments javascripts purs, serveis REST... Tot això està molt lluny dels llenguatges i tecnologies "corporatives", però són les tecnologies que formen la base de les noves aplicacions d'Internet, de la innovació.
Les empreses hauran d'elegir si prefereixen quedar-se en un sector madur i anar fent el mateix que tothom, o començar a apostar per la innovació i jugar-se-la de tant en tant amb projectes i tecnologies no tant consolidades però amb molta projecció.
Els riscs hi són, però ja se sap, qui vol peixos ...
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python Django
Consultes dinàmiques a Django
Escrit per Aaloy a 15 de October , 2009 a les 9 p.m.
Estic mirant de fer un poc més fàcil la integració de jqGrid amb Django, integrar la paginació ha estat força senzill ja que jqGrid i Django fan servir un conjunt de variables semblant: plana actual, total de registres i llista de registres.
jqGrid passa aquests paràmetres per GET quan feim un camvi de plana, per tant podem aprofitar l'objecte paginator de Django per fer la paginació com si fos una aplicació HTML clàssica, sols que en lloc d'HTML retornarem JSON (o XML).
La cosa es complica un poc més quan es tracta de cercar. jqGrid fa servir quatre paràmetres: _search, que es posa a true quan s'ha activat la cerca, searchField que conté el camp pel qual es cerca. SearchField retorna el contingut de la variable index de colModels si existeix o bé el nom. Llavors tenim també searchOper que ens informa del tipus de cerca que es vol fer. Per exemple, passa eq per indicar la coincidència exacta, ew per indicar acaba amb i cn correspon a la sentència IN d'SQL. Per acabar searchString conté el valor del que estam cercant.
Així doncs es tracta de montar un filtre de manera dinàmica amb Django a partir dels valors que ens envia el jqGrid. El primer que hem de fer és fer la taula d'equivalències que mapejarà cada operació de jqGrid amb una operació equivalent de Django.
Per exemple:
1 2 3 4 | django_equivalences = { 'eq': '%s__iexact', 'lt': '%s__lt', 'le': '%s__lte'} |
Això éns permet convertir fàcilment una expressió d'igualtat per a un camp amb l'equivalent Django
1 2 | field = self.request.GET.get('searchField') op = request.GET.get('searchOper') % field |
Amb això ens trobam amb dos problemes: què feim amb les condicions del tipus "no és igual a" o "no comença amb" i què feim amb les expressions "in". I si m'apurau amb un problema més, com passam aquestes condicions que constriuim (o construirem) dinàmicament a Django. Perquè Django espera construccions del tipus Entry.objects.filter(id__gt=4) i nosaltres el que farem és construir-les.
Si ens fixam en la documentació veurem que el problema dels inclosos i dels exclosos està resolt per filter i excludes. Amb la mateixa construcció i generant la consulta amb excludes en lloc de filter ja ho tenim. Sols necessitam doncs que el mapeig a més de la plantilla ens retorni el tipus a que correspon filter o bé excludes.
1 2 3 4 | django_equivalences = { 'eq': ('filter', '%s__iexact'), 'ne': ('exclude','%s__iexact'), 'lt': ('filter', '%s__lt')} |
Suposant que la nostra classe es diu Entry podríem fer quelcom semblant a això:
1 2 3 4 5 6 7 | searchField = request.GET.get('searchField') op = self.request.GET.get('searchOper') value = request.GET.get('searchString') tipo, filtro = django_equivalences[op] query = {filtro%searchField:value} record_list = Entry.objects.filter(**query) if tipo == 'filter' \ else Entry.objects.exclude(**query) |
Fitxem-nos com hem fet la construcció dinàmica. En lloc de crear el codi el que feim és crear un diccionary query que té com a clau l'operació de filtratge damunt el camp que jqGrid ens passa i com a valor, el que volem cercar.
Ens queda encar un petit detall, què passa amb l'in, a Django mapejaria com icontains i espera una llista de valors com a paràmetre. Està clar que ho podríem tractar com un cas particular, però anem-ho a fer divertit, el que farem serà afegir una funció com a valor del mapeig que ens dirà el que hem de fer amb el valor, llevat de in i ni (includes i not includes) no s'ha de fer res, millor dit la funció ha de retornar el mateix valor que li passam (us sona la funció identitat?) i en cas contrari convertirem el valor que ens passi a una llista de valors mitjançant el mètode split(',').
Així doncs el nostre mapeix seria:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | identity = lambda x:x django_equivalences = { 'eq': ('filter', '%s__iexact', identity), 'ne': ('exclude','%s__iexact',identity), 'lt': ('filter', '%s__lt',identity), 'le': ('filter', '%s__lte',identity), 'gt': ('filter', '%s__gt',identity), 'ge': ('filter', '%s__gte',identity), 'bw': ('filter', '%s__istartswith',identity), 'bn': ('exclude','%s__istartswith',identity), 'in': ('filter', '%s__in',lambda x: x.split(',')), 'ni': ('exclude','%s__in',lambda x: x.split(',')), 'ew': ('filter', '%s__iendswith',identity), 'en': ('exclude','%s__iendswith', identity), 'cn': ('filter', '%s__icontains', identity), 'nc': ('exclude','%s__icontains', identity) } field = request.GET.get('searchField') op = self.request.GET.get('searchOper') value = request.GET.get('searchString') try: tipo, filtro, f = django_equivalences[op] except KeyError: tipo, filtro, f = django_equivalences['eq'] filtro = str(filtro % field) query = {filtro:f(value)} record_list = Entry.objects.filter(**query) if tipo == 'filter' \ else Entry.objects.exclude(**query) |
Com veis un exercici interessant perquè hi ha un poc de tot: funció lambda, us dels diccionaris, ús de les funcions com a objectes i pas de paràmetres a una funció mitjançant un diccionari.
Traducciones/Translations by apertium
1 comentari, 0 trackbacks (URL) , Tags: Python Django
Prova de concepte: APSLHOTELS
Escrit per Aaloy a 11 de October , 2009 a les 10:15 a.m.
Ahir al vespre vàrem obrir al públic la nostra prova de concepte del que pot ser una plana de reserves d'hotels: http://hotelestest.apsl.net/. I quan dic prova de concepte en refereixo a poder mostrar el que es pot fer amb la tecnologia Python+Django.
A la nostra comunitat un tant per cent elevat de la informàtica gira al voltant del negoci turístic. Quan vas a parlar amb algú del sector i li dius que programaràs la seva aplicació amb Python i Django sovint ho troben un poc estrany, estan acostumats al PHP i com a molt al Java o .Net, no veuen clar que es pugui fer.
Aquesta prova de concepte vol mostrar el senzill que és i algunes de les possibilitats que té la tecnologia actualment. Per fer la demostració volíem que la plana es connectàs a un XML/SOAP d'un tercer ja que d'aquesta manera es cobreix l'ús més habitual: fer una aplicació web on el motor i la capa de presentació estan separades per un servei XML. Dels proveïdors amb que contactàrem vàrem tenir molt bona acollida i suport de la gent de Valadis/Versys, ens varen donar moltes facilitats des del començament i el seu XML és molt senzill de mapejar. Està clar que les idees que es presenten es poden desenvolupar amb gairebé qualsevol proveïdor XML d'hotels, però vàrem tenir la sort de poder topar amb aquesta gent i que ens donàs accés al seu sistema de proves sense cap problema. Des d'aquí moltes gràcies.
Així doncs, tenim una aplicació B2C que permet reserva hotels i que connecta al motor XML de test d'un proveïdor extern. Com a bon entorn de test he de dir que es troba en contínua evolució i que les dades que es mostren són sols un subconjunt molt limitat de les que es tendrien en un entorn de producció. No us fixeu massa en les dades, sinó en el bessó del que es mostra. Per cert, podeu provar tot el que volgeu, tanmateix no es fa cap tipus de pagament ni control a la tarja que poseu.
Feta aquesta introducció anem a veure un poc la bèstia:
El desenvolupament
Com he dit l'aplicació està desenvolupada fent servir Python+Django, pel control de versions s'ha fet servir Subversion i pel control del projecte s'ha fet servir Trac.
Per crear l'aplicació hem mapejat l'XML a objectes Python amb la llibreria lxml, una llibreria que envolcalla les llibreries C libxml2 i libxslt. La velocitat del C i l'expressivitat de Python.
Per la depuració i programació hem fet servir: django-extensions, debug_toolbar, ipdb i ipython. La primera llibreria ens proporciona tot un conjunt de funcions còmodes per l'administració de l'aplicació, debug_toolbar ens diu quina plantilla es fa servir en cada pantalla, les seves herències, les sql que es generen, etc. ipdb és un depurador de línia de comandes, com el pdb però amb autocompletat i ressaltat de sintaxi. ipython és una consola Python, Django l'aprofita si està instal·lada, proporciona autocompletat, resaltat de sintaxis i un gran nombre de comandes extra.
Els editors més habituals han estat Netbeans, Eclipse, Vim, Kate i Notepad++ (per Windows). L'editor importa poc, tots estan configurats per fer feina amb UTF-8 i els tabuladors configurats a 4 espais. Amb això en tenim prou per poder fer servir en qualsevol moment l'editor que més ens agradi. Particularment vaig d'un a l'altra segons la màquina que faig servir.
Per les planes de contingut estàtic hem fet servir django-page-cms, la idea és mostrar com un gestor de continguts es pot integrar dins l'aplicació.
Els css i js es comprimeixen abans de servir-se gràcies a django-compress. Això vol dir que podem fer cachés mesos. Quan el css o el js canvii sols hem de tornar a generar els arixus comprimits i la llibreria els posa un nou nom.
La configuració de sistemes
L'aplicació s'executa en un chroot propi dins un servidor propi que duu moltes més aplicacions.
vendor_id : GenuineIntel cpu family : 6 model : 15 model name : Intel(R) Pentium(R) Dual CPU E2180 @ 2.00GHz stepping : 13 cpu MHz : 1994.999 cache size : 1024 KB top - 08:52:55 up 729 days, 13:56, 0 users, load average: 0.07, 0.02, 0.00 Tasks: 126 total, 1 running, 125 sleeping, 0 stopped, 0 zombie Cpu(s): 0.0%us, 0.2%sy, 0.0%ni, 99.8%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st Mem: 1015232k total, 984036k used, 31196k free, 154472k buffers Swap: 2097144k total, 2948k used, 2094196k free, 90536k cached
L'entorn d'execució s'independitza de la màquina amb aquest chroot i a més es va crear un entorn virtual separat per l'aplicació amb virtualenv, això permet tenir un control total damunt les llibreries i el Python Path.
Seguint les millors pràctiques, hem separat els dominis que serveixen el contingut estàtic del contingut dinàmic. Això és prou senzill amb Django i sols has de recordar escriure les url amb {{MEDIA_URL}}.
Donat que és una màquina amb altres aplicacions volíem que el consum de memòria fos mínim. Per això hem optat per que el servidor http no fos un Apache sinó nginx que tenim configurat tant per servir el contingut estàtic com per a fer de proxy invers cap al motor WSGI que executa l'aplicació Django.
Pel motor WSGI triarem CherryPy (d'aquí no res posarem Tornado). Amb això tenim una relació de consum de recursos de màquina i rendiment molt òptima i una escalabilitat horitzontal fabulosa. Posant-hi un balancejador podem anar copiant i aferrant chroots i dins cada chroot podem tenir tantes instàncies de l'aplicació con suporti la màquina.
És veritat que no calia complicar-se tant per a una prova de concepte, però la idea no és tan sols mostrar el que es pot fer en programació, sinó com la tecnologia i el frameworks s'adapten a les necessitats actuals i futures de rendiment. És a dir, que s'escala cap amunt i cap avall.
L'aplicació
A la primera plana hi trobam el cercador, el típic cercador afegiria. Aquí utilitzam jquery-ui pels widgets de calendari. Hi ha la demostració de l'autocompletat als apartats de destinos i nombre de hotel.
El errors es mostren a la plana de manera poc intrusiva. Per això s'utilitzen plugins de jquery i les capacitats de serialització json de Python i Django, junt amb la validació de formularis de Django. És molt més senzill del que sona.
També es pot veure la utilització que es fa del CMS en les planes de Aviso Legal per exemple i també hi podem trobar dos tipus d'ofertes.
Aquestes es mantenen dins la part d'administració. No són gaire sofisticades, però serveixen per mostrar el dinamisme que es pot aconseguir i el concepete d'url semàntica.
Picant damunt una oferta per exemple, anirem a la plana de resultats. Recordem que anam contra un entorn de proves i que les dades són les que són. La idea és poder mostrar com les dades de l'hotel es carreguen dinàmicament mitjançant una cridada AJAX i com l'aplicació manté en sessió les dades de la selecció.
Hem posat també un filtre js. Pitjant damunt el filtre de categoria desapareixen els hotels amb aquesta categoria. Es pot utilitzar el mateix concepte per a filtrar els resultats per altres camps (preu, tipus d'habitació, ...)
A partir d'aquí ja anam a les pantalles que obtenen la informació de compra i a la de gràcies. Res destacable en aquest punt que no hagi sortit abans.
Pas a producció
Hi ha gent que ens ha demanat pel pas a producció d'aquesta aplicació. Recordau que és una prova de concepte, no hi haurà pas a producció, serveix per mostrar idees de programació, conceptes tecnològics i d'optimització.
El que si es pot fer és desenvolupar una solució a mida amb aquestes tecnologies, però serà sempre per a un tercer i si es fes hi hauria molta feina que en la prova de concepte s'ha obviada:
- Continguts estàtics: hem posat lorem ipsum gairebé per tot.
- Filtres
- Paginació de resultats
- Connexió amb una passarel·la de pagament
- Generació del bono
- Enviament del bono al client
- Backoffice de control
L'aplicació tal com està i en les seves possibles evolucions té per objectiu que gent com nosaltres que ens dedicam al desenvolupament Python i Django poguem mostrar al món turístic el que es pot fer. Consideram l'aplicació com un Projecte Mascota: hi anam dedicant hores quan ens fa ganes.
Traducciones/Translations by apertium
2 comentaris, 0 trackbacks (URL) , Tags: Python Django
Simple Web services
Escrit per Aaloy a 23 de September , 2009 a les 8:33 p.m.
L'altra dia ens van donar un "curset" d'introducció a TIBCO i ho pos entre cometes perquè curset potser no és la paraula adient, ja que més aviat va ser una presentació comercial. Tot i això i entre capada i capada d'avorriment vaig tenir l'ocasió de parlar amb el formador (o deformador) dels serveis dins les possibilitat que ofereix TIBCO. Deia que era molt senzill agrupar serveis i generar el WSDL corresponent per a ser consumit fàcilment per altres aplicacions.
No dubt que això sigui així però les meves reticències fonamental venen donades pel fet de que quan vols que el teu servei sigui consumit externament, el que has de fer és facilitar al màxim que la gent ho pugui fer.
El SOAP és un protocol que va néixer per ser simple i que ha acabat essent complexe fins al punt de fer-se immanejable, sobre tot gràcies a les extensions que es varen introduir per a facilitar-ne la creació i consum per llenguatges concrets. L'article de Peter Lacey del 2006, anomenat The S Stands for Simple en fa una discussió emprant el mètode socràtic que s'ho paga llegir.
Quan per raons de negoci (el cap ho ha exigit, per dir-ho més clar) hem tingut que fer els web services amb SOAP el que hem procurat sempre és controlar molt bé el resultat final del WSDL de manera que fos fàcilment consumible tant pel qui l'ha creat (Java en el nostre cas) com per altres llenguatges (Python per exemple). Aquest resultat difícilment s'obté si qui genera el SOAP suposa que és el mateix que l'ha de consumir i per tant no veu la complexitat des del punt de vista d'un tercer, sinó que genera el WSDL de manera que la transformació inversa li sigui favorable.
Per una altra banda afegir la capa SOAP i consumirla té un cost (el famós payload) en termes de capacitat de procés i ampla de banda. Si alguan cosa té és que entre namespaces, definicions i subdeficinions, un missatge que podria de ser de pocs bytes multiplica el seu pes per 100 o per 1000.
Per una altra banda, la complexitat del WSDL fa que sovint no basti el WSDL com a documentació (un dels objectius del SOAP) sinó que s'ha d'adjuntar una documentació addicional explicant cada missatge, quins són els paràmetres, etc. Així que argumentar que el WSDL s'autodocumenta és pecar un poc d'ingenuo i optimista.
El SOAP és bo si es mantén simple, el problema és que fer-ho simple i consumible fàcilment duu molta feina i se suposava que això ens ho hauria d'evitar.
Ara mateix l'alternativa és tornar a la simplicitat. Evitar la sobrecàrrega de feina de màquina i gent que suposa el SOAP i anar cap a protocols més senzills:
-
XML+HTTP. Amb una eina d'extracció de documentació podem fer la web de documentació i proves al mateix temps que escrivim el servei. Activant la compressió del gzip del servidor ens queda tot d'allò més compacte.
-
XML-RPC. Anam un poc més enllà. Podem consumir l'XML com si d'una llibreria es tractàs. Igual que abans la documentació dins el codi ens pot permetre estalviar molta feina. David Fisher ha fet un exemple molt instructiu amb Django d'aquest concepte.
-
Json-RPC o Json+HTTP. El Json s'ha convertit en un format d'intercanvi potent i senzill. Perquè no utilitzar-ho? Es pot consumir gairebé des de qualsevol llenguatge modern i la transformació a objectes nadius és trivial.
-
REST. Utilitzam les URL si l'HTTP per al nostre intercanvi d'informació. És el que mou la web. Se li ha donat un nom i un conjunt de criteris per a formalitzar el mecanismes d'accés als serveis.
El gran avantatge de tot això és que la generació del servei no requereix de llenguatges "empresarials", sinó que ho podem fer fins i tot amb qualsevol microframework (web.py, Tornado, ...) amb Django o amb qualsevol cosa que ens permeti respondre a una petició http i tractar-ne les capçaleres.
Per Django per exemple tenim el projecte Django-Piston que ens permet crear una API REST per als nostres projectes d'una manera molt poc intrusiva.
Fa una bona temporada que el SOAP i els WSDL que hem fet sols estan en manteniment. Si els tengués que fer ara i depengués de mi o serien serveis REST o bé XML purs i segurament tampoc estarien fets en Java.
Traducciones/Translations by apertium
3 comentaris, 0 trackbacks (URL) , Tags: Informàtica Python Django
Comenta, que serveix
Escrit per Aaloy a 21 de September , 2009 a les 9:02 p.m.
Quan un fa programes per aprovar l'assignatura sap que ha de posar comentaris perquè si no no és considera un codi professional, així que els posam per obligació, perquè hi han de ser, però potser sense adonar-nos de la seva utilitat real.
Els programes que feim per aprovar rarament són molt complexos, són exemples que es poden fer en poques setmanes i que rarament s'hauran de mantenir. La vida real és força diferent, els programes tenen un cicle de vida llarg, d'anys o dècades i s'han de fer millores correctives i adaptatives.
Aquell programa que ahir teníem molt clar al cap d'uns anys potser ja no ho tindrem tant i els comentaris que posàrem faran que tot ens resulti molt més fàcil d'entendre. I ja no diguem res si no som nosaltres el que hem de mantenir el codi!
Els bons comentaris ens haurien de dir el perquè del codi, què fa, què espera a l'entrada i què a la sortida. El codi ens dirà com ho fa. Això vol dir que el codi també ha de ser llegible, teclejar una mica més no costa tant i podem posar noms a les variables, a les classes, a les funcions, que tenguin significat.
Python per exemple té dues castes de comentaris, els que es fan servir per documentar el per què, i que sovint es presenten en forma de cometes triples i que es lliguen al doc (i a l'ajuda) de l'objecte i els comentaris fets amb la parrilla (#) que s'han de fer servir per comentar aspectes del codi que no necessitin. Java té quelcom semblant.
Però podem anar una mica més enllà. L'altra dia al twitter algu deia que li quedava fer la documentació de la pràctica. També molt habitual :) Posar bons comentaris ens pot estalviar una bona feina i no tan sols això, sinó que serà text de qualitat ja que s'ha fet amb menys presses i amb la ment més fresca en relació al que se està fent.
I encara una utilitat més: el pseudocodi. Particularment quan he de fer una cosa complexa començ per escriure'n les passes i les pos en forma de comentari. D'aquesta manera tenim més clar el que s'ha de fer i el temps s'aprofita, ja que aquest pseudocodis seran després els comentaris que ajudaran a seguir millor el codi.
No vull acabar sense citar una eina fantàstica per a la documentació: l'Sphinx us podeu adonar d ela bona feina que fa amb la documentació de Python o Django per exemple. Sphinx té una cosa molt bona, ens permet extreure els comentaris del nostre codi Python i afegir-los a la documentació, de manera que du el reaprofitament i la màxima DRY al món dels comentaris i la documentació. Per poc que us agradi el RestructuredText no deixeu de fer-li una ullada a aquesta eina, fins i tot si no programau en Python.
Per cert, en el seu dia vaig deixar un petit tutorial de RestructuredText a Bulma.
Traducciones/Translations by apertium
2 comentaris, 0 trackbacks (URL) , Tags: Python Django
Django CherryPy vs Tornado
Escrit per Aaloy a 14 de September , 2009 a les 7:28 p.m.
Fa pocs dies s'ha alliberat un motor web anomenat Tornado part de la tecnologia que mou FriendFeed.
És un servidor no bloquejant que promet molt en quan a velocitat, pensat per moure FriendFeed i escalar la càrrega que faci falta.
Independentment de que es pugui desenvolupar amb ell tot una aplicació, sols la part de servidor http ja és prou interessant com per fer-li una ullada. En un post a la llista de Django Bret Taylor, un dels autors de Tornado, postejava com connectar el motor amb Django mitjançant WSGI.
Actualment una de les configuracions que més m'agraden per desplegar aplicacions és la combinació nginx+CherryPy WSGI+Django (amb balancejadors, memcached i tota la pesca gràcies a la bona feina de Bernat i Pere), així que estava força intrigat per veure com respondria Tornado.
La base estava feta: una mini-aplicació "hello world" que vaig escriure per comparar aquesta tecnologia/arquitectura amb diferents frameworks PHP, així que ha está un no res actualitzar la darrera versió de CherryPy WSGI i crear una nova aplicació semblant per Tornado.
El codi font és a:
I ara els resultats:
La màquina és un PPC 1 Gb de RAM, 2 CPU de 2 GHz
Amb Tornado WSGI:
ab -c 10 -t 60 http://localhost:8888/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient)
Completed 5000 requests
Completed 10000 requests
Completed 15000 requests
Completed 20000 requests
Completed 25000 requests
Finished 25022 requests
Server Software: TornadoServer/0.1
Server Hostname: localhost
Server Port: 8888
Document Path: /
Document Length: 266 bytes
Concurrency Level: 10
Time taken for tests: 60.019 seconds
Complete requests: 25022
Failed requests: 0
Write errors: 0
Total transferred: 9333206 bytes
HTML transferred: 6655852 bytes
Requests per second: 416.90 [#/sec] (mean)
Time per request: 23.987 [ms] (mean)
Time per request: 2.399 [ms] (mean, across all concurrent requests)
Transfer rate: 151.86 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.1 0 6
Processing: 3 24 1.9 24 68
Waiting: 0 24 1.9 23 68
Total: 7 24 1.9 24 68
Percentage of the requests served within a certain time (ms)
50% 24
66% 24
75% 24
80% 24
90% 25
95% 26
98% 27
99% 28
100% 68 (longest request)
Usant CherrPy amb 3 threads (la millor configuració per la meva màquina segons les meves proves)
ab -c 10 -t 60 http://localhost:8088/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient)
Completed 5000 requests
Completed 10000 requests
Completed 15000 requests
Completed 20000 requests
Finished 21500 requests
Server Software: CherryPy/3.0.3
Server Hostname: localhost
Server Port: 8088
Document Path: /
Document Length: 266 bytes
Concurrency Level: 10
Time taken for tests: 60.001 seconds
Complete requests: 21500
Failed requests: 0
Write errors: 0
Total transferred: 8299000 bytes
HTML transferred: 5719000 bytes
Requests per second: 358.33 [#/sec] (mean)
Time per request: 27.907 [ms] (mean)
Time per request: 2.791 [ms] (mean, across all concurrent requests)
Transfer rate: 135.07 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 20.5 0 2999
Processing: 3 28 10.7 26 413
Waiting: 3 26 10.3 24 412
Total: 3 28 23.1 26 3031
Percentage of the requests served within a certain time (ms)
50% 26
66% 28
75% 30
80% 31
90% 34
95% 38
98% 43
99% 48
100% 3031 (longest request)
En resum:
416.90 req/s for Tornado WSGI 358.33 req/s for CherryPy
Tornado fa que una CPU es posi al 100% gairebé des del començament de l'execució de la comanda ab, CherryPy també posa la CPU al 100% però ho fa més tard i potser això explica la diferència, potser algún gurú de CherryPy em podrà dir una configuració millor que la que tinc.
58 peticions representen un 16% més de peticions que pot aguantar Tornado respecte de CherrPy, i si us hi fixau el codi que es necessita per executar-hi Django és pràcticament calcat gràcies al WSGI.
Seguesc fent proves, però per ara la cosa pinta molt bé.
Traducciones/Translations by apertium
2 comentaris, 0 trackbacks (URL) , Tags: Python Django
Decoradors a Python
Escrit per Aaloy a 30 de August , 2009 a les 7:22 p.m.
Què és un decorador
Un decorador és el nom d'un patró de disseny. Els decoradors alteren de manera dinàmica la funcionalitat d'una funció, mètode a classe sense tenir-ne que fer subclasses o canviar el codi font de la classe decorada. En el sentit de Python un decorador és quelcom més, inclou el patró de disseny, però van més allà, Bruce Eckel els assimila a les macros de Lisp.
Els decoradors i la seva manera d'utilitzar-se ens ajuden a fer el nostre codi més net, a autodocumentar-lo i a diferència d'altres llenguatges de programació no requereixen que ens aprenguem un altre llenguatge de programació (com passa amb les anotacions de Java per exemple). En la seva utilització podem atracar-nos a la programació orientada a aspectes (AOP) o utilitzar-los per a afegir sistemes de control a les nostres funcions, de log, caché, ... Les possibilitats són infinites. El decoradors formen part de Python des de la versió 2.4 i com diu Michele Simionato ens aporten el següent:
- Redueixen el codi comú i repetitiu (l'anomenat codi boilerplate).
- Afavoreixen la separació de responsabilitats del codi
- Augmenten la legibilitat i la mantenibilitat
- Els decorador són explícits.
Aquesta potència té un preu: en rendiment (que s'haurà d'avaluar per a cada aplicació) i en complexitat a l'hora de desenvolupar-los. Un decorador típic veurem que és molt bo d'escriure, però la cosa es complica un poc quan volem passar paràmetres o mantenir la signatura del mètode. Aquesta complexitat no és tant pel codi que s'ha d'escriure sinó perquè hem de recordar com s'ha d'escriure el decorador per a cada cas.
Afortunadament veurem que gent com Michele Simionato han desenvolupat paquets que ens simplifiquen molt la vida. Tot i això i abans de fer servir aquestes utilitats convé saber què són i desenvolupar-los sense ajuda. És un poc com aprendre's les taules de multiplicar i després ja utilitzar la calculadora.
Classificació dels decoradors
Podem dividir els decoradors en grups:
- Segons els paràmetres que admeten:
- No admeten paràmetres
- Sí admeten paràmetres
- Segons si preserven la signatura del mètode al que decoren:
- Decoradors no que preserven la signatura
- Decoradors que si la preserven
Els decoradors més senzill són aquells que no admeten paràmetres i no preserven la signatura
Un decorador que no fa res
Per començar crearem un decorador que el que farà es convertir qualsevol funció en un /dev/null, és a dir, no retornarà res i no farà res amb la funció.
1 2 3 4 5 6 7 8 | def forat_negre(f): def none(): pass return none @forat_negre def di_hola(): return "hola" |
Si executam di_hola() no tendrem cap resultat, millor dit tindrem None
La sintaxi @ del decorador de Python és el que s'anomena syntactic sugar, és a dir, una manera d'escriure les coses que ens simplifica la legibilitat, però fet i fet es podria escriure perfectament com
1 2 | di_hola = forat_negre(di_hola) di_hola() |
i tendríem el mateix que fa el decorador. Recordem que les funcions són objectes i que es poden assignar i passar com a paràmetres a Python.
Tot i la senzillesa de l'exemple ens serveix per veure el següent:
Un decorador no és més que un envolcall cap a una funció i per tant ha de retornar una funció, més concretament un callable, per a entendre'ns, qualsevol cosa que posant-hi un doble parèntesi al costat () no peti.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | def retorna_objecte(f): ....: def obj(): ....: return object() ....: return obj ....: In [17]: def di_hola(): ....: return "Hola" ....: In [18]: di_hola = retorna_objecte(di_hola) In [19]: di_hola() Out[19]: <object object at 0xf7f745e8> |
Al nostre decorador forat_negre li hem passat una funcició sense paràmetres, però si li passam paràmetres ens trobarem una sorpreseta
1 2 3 4 5 6 7 8 | @forat_negre def suma(a,b): return a,b suma(2,3) TypeError Traceback (most recent call last) TypeError: none() takes no arguments (2 given) |
que per una altra banda és del tot normal, hem definit el forat_negre de tal manera que retorna una funció sense paràmetres, així que si li intentam passar els paràmetres que tenia la funció decorada senzillament es queixa i peta.
Anem a definir un poc millor el nostre decorador per a que no ens passi així i poder admetre el mateixos paràmetres que la funció decorada
1 2 3 4 5 6 7 8 9 10 11 12 | def forat_negre(f): "d'aquí no surt res" def none(*args, **kw_args): pass return none @forat_negre def suma(a,b): "suma dos parametres qualsevols si pot" return a+b suma(2,2) |
Ara ja no dona error. Així doncs una altra conclusió: a més de tornar una funció, hem de procurar que la definició de las funció que tornam admeti al manco els mateix nombre de paràmetres que la funció que volem decorar. Si no sabem quants són aquests ens curam en salut amb args i kw_args.
Fixem-nos que no hem mantingut la signatura de la funció i com a experiment intentau fer un help(suma). Tornarem damunt això un poc més endavant. Ara per ara ja sabem com crear decoradors simples a partir d'una funció.
Fent decoradors no intrusius
Si heu fet un help(suma) o un suma.__name__ potser un haureu sorprés en veure que le nom de la funció és none en lloc de l'esperada suma. Si pensau amb el que hem fet tampoc és d'extranyar, fet i fet hem substituït la funció original per
una altra, recordem que el decorador f aplicat damunt la funció g és equivalent a fer g = f(g).
El que és aconsellable és que el decorador sigui capaç de mantenir la documentació i el nom de la funció que decora, ja que d'aquesta manera es simplifica l'ús de la funció i els autocompletadors de codi no es tornen bojos.
Això ho podem fer de dues maneres: la llarga i la curta
La manera llarga
1 2 3 4 5 6 7 | def forat_negre(f): def none(*args, **kw_args): pass none.__doc__= f.__doc__ none.__dict__= f.__dict__ none.__name__= f.__name__ return none |
Amb les tres instruccions adicionals que hem posat tornar a recuperar les metadades de la funció original que passam al decorador. Si hara feim un help veurem que es fa damunt el nom de la funció correcta suma i que l'ajuda també és la seva.
Help on function suma in module __main__:
suma(*args, **kw_args)
Suma dos parametres qualsevols si pot
Fixem-nos en la signatura de la funció no s'ha preservar. Abans admetia dos paràmetres i ara n'admet un nombre qualsevol. Per la majoria de casos això no té més importància, però al final de l'article veurem com es pot resoldre.
La manera curta
Com que el tema de reservar les metadades és força interessant i comú, al mòdul functools hi trobam la funció wraps que és en sí mateixa un decorador i que fa aquesta funció. D'aquesta manera el codi anterior quedaria:
1 2 3 4 5 6 7 | from functools import wraps def forat_negre(f): @wraps(f) def none(*args, **kw_args): pass return none |
Fixau-vos que hem fet servir un decorador per crear un altre decorador. Insistirem en aquest tema més tard.
Un decorador amb arguments
El decorador que hem fet a l'apartat anterior era prou simple, feia ben poca cosa i no tenia paràmetres. Si volem fer decoradors hem de fer primer de tot que siguin útils, i també ens trobarem amb la necessitat de que aquests decoradors admetin paràmetres.
A Django, per exemple, podeu trobar que el decorador de cache admet paràmetres que ens permet dir-li durant quan de temps ha de cachejar els resultats, o el decorador vary_on_headers, que ens permet modificar el contingut de la resposta de les vistes afegint les capçaleres que indiquem.
Anem a veure com ho podem aconseguir nosaltres. També hi ha dues maneres de fer-ho, la clara i la complexa. La manera clara és la que recoman i utilitza una classe per a fer el decorador, la complexa requereix més esforça per a entendre què està fent el decorador, és més curta, però personalment preferesc un codi més legible.
De la mateixa manera els decoradors que hem fet com a funcions es poden crear com a classes, però en aquest cas, crec que la definició en forma de funcions és més bona de seguir, i ens permetrà distingir clarament entre els dos tipus de decoradors: el que no admeten paràmetres que es construeixen preferentment mitjançant funcions i els que admeten paràmetres, que es construeixen preferentment fent servir classes.
Per seguir amb el forat negre, ara el nostre exemple el que farà es mostrar el resultat o no segons li roti. Per això el que farem serà passar-li una funció com a paràmetre que en ser executada determinarà si s'ha de mostrar el resultat de la funció decorada o no
El mètode clar de fer decoradors amb arguments
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/usr/bin/env python # -*- coding: UTF-8 -*- import random class forat_negre_sonat(object): "Un decorador amb fam" def __init__(self, mostrar): self.mostrar = mostrar def __call__(self, f): def none(*args, **kw_args): if self.mostrar(): return f(*args, **kw_args) else: return "Nop" return none @forat_negre_sonat(mostrar = lambda :random.choice((True, False))) def suma(a, b): "Suma dos elements que li passam com a paràmetre" return a+b if __name__=="__main__": print suma(2,3) print suma(5,6) print suma(9,5) |
Fitxem-nos amb que hem fet:
-
Hem creat una classe Python que al seu constructor (l'init) agafa el paràmetre o paràmetres que vulguem. És un constructor normal, així que admet paràmetres per defecte per exemple.
-
Recordem que el decorador hem dit que ha de ser un objecte cridable (callable), a una classe, la cridabilitat la dóna el mètode call. Aquesta classe la definirem de manera que agafi la funció a decorar com a paràmetre. D'aquesta manera tenim accés tant als paràmetres del decorador, que hem passat al constructor, com a la funció decorada, que hem passat com a paràmetre al call.
Després d'això ja sols en queda encapsular la cridada com ho fèiem al cas anterior, retornant el decorador en lloc de la funció decorada.
A l'exemple el que he fet és mostrar que el paràmetre pot ser el que nosaltres vulguem, en concret he passat una funció anònima, creada amb lambda que és la que s'encarrega d'establir l'aleatoritat del resultat.
Si voleu podem fer aquest decorador una mica més complet, fent que admeti a més de funcions valors i que preservi el nom i documentació de la funció decorada.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | #!/usr/bin/env python # -*- coding: UTF-8 -*- import random class forat_negre_sonat(object): "Un decorador amb fam" def __init__(self, mostrar=None): self.mostrar = mostrar def __call__(self, f): def none(*args, **kw_args): if callable(self.mostrar): opcion = self.mostrar() else: opcion = self.mostrar if opcion: return f(*args, **kw_args) else: return "Nop" none.__name__ = f.__name__ none.__doc__ = f.__doc__ return none @forat_negre_sonat(mostrar = lambda :random.choice((True, False))) def suma(a, b): "Suma dos elements que li passam com a paràmetre" return a+b @forat_negre_sonat(mostrar=True) def resta(a,b): return a-b if __name__=="__main__": print "Exemple amb %s " % suma.__name__ print suma(2,3) print suma(5,6) print suma(9,5) print "Exemple amb %s " % resta.__name__ print resta(2,3) print resta(5,6) |
El mètode enrevessat de fer decoradors amb arguments
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | def forat_negre_dos(mostrar): def wrap(f): @wraps(f) def wrapped_function(*args, **kw_args): if callable(mostrar): opcion = mostrar() else: opcion = mostrar if opcion: return f(*args, **kw_args) else: return "Nop" return wrapped_function return wrap |
Bé, enrevessat, el que es diu enrevessat no ho és, per una cosa tan simple no té massa història, però fixau-vos que és un poc més mal de seguir.
El primer que hem fet és definir la nostra funció, on hi hem posat els paràmetres que admet. Aquest funció retorna una altra funció que admet un argument, que és la funció decorada, que a la seva vegada admet un nombre indeterminat d'arguments (recordem que això ho estam forçant nosaltres).
Com que la segona funció, wrapped_function està definida dins wrap, té accés al paràmetre del decorador i pot actuar en conseqüència.
Encadenant decoradors
Els decoradors es poden encadenar, és a dir, una funció pot tener tans decoradors com faci falta i necessitem, sols limitats pel nostre sentit comú i la legibilitat del programa. Dos decoradors són habituals, tres no es veuen gaire, quatre o més són per pensar-s'ho.
Per a l'exemple manllevaré un dels decoradors més útils, el memoize, que ens permet cachejar una funció segons els seus paràmetres. Al Python Decorator Library hi ha una implementació del patró memoize prou senzilla de seguir amb el que ara sabem i a més ens servirà per completar la construcció de decoradors sense paràmetres fent servir una classe.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | class memoized(object): """Decorator that caches a function's return value each time it is called. If called later with the same arguments, the cached value is returned, and not re-evaluated. """ def __init__(self, func): self.func = func self.cache = {} def __call__(self, *args): try: return self.cache[args] except KeyError: self.cache[args] = value = self.func(*args) return value except TypeError: # uncachable -- for instance, passing a list as an argument. # Better to not cache than to blow up entirely. return self.func(*args) def __repr__(self): """Return the function's docstring.""" return self.func.__doc__ |
A diferència de la construcció amb paràmetres, al constructor de la classe memoized s'hi posa com a paràmetre la funció a decorar, i al mètode call hi van els paràmetres de la funció, en lloc de la funció a decorar com es feia a l'altre mètode.
Per què s'ha fet servir aquesta manera si l'altra és més senzilla? Dons perquè necesitam mantenir en memòria la caché i el que fa és mantenir-la en un diccionari dins de la mateixa classe. Si la caché fos externa (amb memcached per exemple), això s'hauria pogut fer perfectament en forma de funció.
A més definirem un decorador que ens servirar per indicar quan entram a la funció i comprovar el decorador memoized.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | def log(f): "Registra l'execució de la funció" def wrap(*args): print "Excutant %s, args: %s" % \\ (f.__name__, ",".join(str(x) for x in args)) return f(*args) return wrap @memoized @log def fibonacci(n): "Return the nth fibonacci number." if n in (0, 1): return n return fibonacci(n-1) + fibonacci(n-2) print fibonacci(12) |
Provau d'executar aquest codi amb i sense la funció memoized. Amb els dos decoradors activus veureu que el cada decorador agafa com a entrada la funció ja decorada que surt del decorador que té més avall. Així el memoized agafa com a entrada la funció fibonacci ja decorada amb el log.
Podeu fer la prova amb un exemple més simple:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | #!/usr/bin/env python # -*- coding: UTF-8 -*- def uppercase(f): "Dada una función f que devuelve un string lo pasa todo a mayúsculas" def wrap(): return f().upper() return wrap def make_bold(f): "Dada una función f que devuelve un string le añade los tags de bold" def wrap(): return "<strong>%s</strong>" % f() return wrap @make_bold @uppercase def say_hello(): return "Hello world" print say_hello() |
Provau canviant l'ordre dels decoradors i veureu perfectament com es van aplicant els decoradors des de la funció per amunt. A l'exemple primer es converteix el "Hello word" a majúscules i després se li apliquen els tags de negreta.
La signatura pendent
Abans d'acabar ens queda un tema pendent: la signatura. Els decoradors que hem creat poden preservar el nom i la documentació de la funció que decoren, però no preserven la signatura, és a dir, el nombre de paràmetres que li passam.
Michele Simionato ha escrit un mòdul excel·lent anomenat decorator que extén la utilizació dels decoradors, mantén la signatura de la funció, el nom i la documentació, i a més ens dona la possibilitat de crear factories de decoradors. Una eina per a tenir sempre a mà. Amb aquest mòdul podríem escriure el codi de l'exemple anterior com:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | from decorator import decorator @decorator def uppercase(f, *args): "Donada una funció f que retorna un string ho passa a majúscules" return f(*args).upper() @decorator def make_bold(f, *args): "Afegeix el tag strong a la sortida de la funció" return "<strong>%s</strong>" % f(*args) @uppercase @make_bold def say_hello(nom): "Di hola, home!" return "Hello world %s" % nom if __name__=="__main__": from inspect import getargspec print say_hello('World') print say_hello.func_name print say_hello.__doc__ print getargspec(say_hello) |
Si executau el codi podem veure que no ens ha fet falta recore a wraps o a reasignar nom, la pròpia llibreria de Simionato ho ha fet. A més, si ens fixam en la sortida de l'exemple:
<STRONG>HELLO WORLD WORLD</STRONG> say_hello Di hola, home! ArgSpec(args=['nom'], varargs=None, keywords=None, defaults=None)
La primera línea correspon a la sortida de la funció que hem decorat. La segona és el nom d'aquesta funció. Ens surt el nom de la funció original i no el del decorador. La documentació també s'ha mantingut i per acabar, podem veure que la signatura de la funció és correcta, ens diu que té un argument obligatori anomenat nom.
Conclusió
Esper haver deixat un poc més clar el tema dels decoradors. Crear-los no és difícil, utilitzar-los és simple, sols hem de tenir clar què són i quan fer-los servir. Són una eina potent que ens permet fer el nostre codi més legible i cohesionat. Fora por i a disfrutar amb els decoradors.
Com tot en aquesta vida, usau-los amb coneixement i moderació.
Referències
Per escriure aquest article m'he basat en múltiples fonts, les més importants i útils han estat:
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python Django
Qooxdoo
Escrit per Aaloy a 20 de August , 2009 a les 10:31 p.m.
Qooxdoo és un bastiment per a la creació d'aplicacion web amb aparença d'escriptori, és a dir el que es coneix com a RIA (Rich Internet Applicatinons).
Aquests darrers dies he estat donant-li una ullada a aquest bastiment. Feia temps que li estava seguint la pista i finalment m'he decidit a avaluar-lo com toca, és adir, començant a fer-hi alguna cosa productiva.
Quan un va a la web de Qooxdoo el primer que pot reparar és que el bastiment compta amb un bon conjunt d'exemples que ens permeten veure les possibilitats del producte. L'aparença de Qooxdoo no és tan cuidada com la d'Extjs per exemple, però en el seu conjunt presenta tota les funcionalitats necessàries.
A l'hora d'avaluar el bastiment m'he fixat en dos punts que per mi són claus: la mantenibiliat de les aplicacions i les seves capacitats de connexió amb altres sistemes.
Donat que el cicle de vida de les aplicacions és molt més llarg que el temps de desenvolupament, tenir un bastiment que ens permeti crear aplicacions mantenibles és fonamental. El bastiment ens ha de permetre estructurar l'aplicació en mòduls i a més ens ha d'abstreure de les complexitats del javascript en el que fa a les colisions de noms.
Qooxdoo resol aquest tema molt bé. No és tan sols un bastiment gràfic, sinó que ha creat un vertader llenguatge orientat a objectes amb les possibilitats bàsiques que ens dóna el javascript. La gent que ve de Java es sentirà com a casa amb aquest model d'objectes: ens permet tenir variables i mètodes estàtics, crear fàcilment mètodes, parla de constructors, d'herència i fins i tot hi ha alguan cosa semblant als interfícies. Aquest model de programació es pot aplicar per modularitzar el codi, de manera que podem crear objectes que representin una finestra amb el seu contingut o bé fer un objecte per a representar un aspecte concret: un menú per exemple.
A l'hora de posar el sistema en producció Qooxdoo se n'encarrega d'esbrinar quins són els mòduls que es fan servir i empaquetar i comprimir els distints mòduls que hem creat en un únic arxiu (més de 500 K a les meves proves). Com es pot veure està força ben pensat, i és una de les coses que més m'han agradat, ja que amb una aplicació gran és molt fàcil perdre la pista del que es fa i acabar amb mega-arxius javascript que tenen un poc de tot. Qooxdoo ens ajuda a estructurar el nostre codi sense perder l'avantatge de poder fer el desplegament a producció amb un únic arxiu javascript.
La connexió amb altres sistemes també em feia passar un poc de pena. Hem connectat bastiments javascript fent servir json, xml i cridades ajax i quan més complexe és el bastiment més dificultats hi ha amb el json, ja que sempre ho esperen d'una determinada manera.
Qooxdoo permet connectar-se mitjançant Ajax i fent servir Json RPC. He creat una sèrie de serveis jrpc de prova amb Django i he mirat de connectar-los. M'ha costat una mica ja que no comptava amb el problema de la seguretat del javascript a IE i Firefox. No es permeten cridades a dominis diferents (crossdomain), però tampoc a ports diferents. Com que Django a desenvolupament ho tenia a localhost:8000 i el javascript ho tenia com a file:// no hi havia manera de fer la connexió per POST. La solució ha esta utilitzar nginx per a servir el javascript i a més per servir de proxy invers cap a Django, amb això ja he pogut fer la connexió sense problemes i tenir el millor dels dos mons, independitzant la capa de presentació de la capa del web service, creat amb el servidor Django i amb capacitat d'autodocumentació, de manera que el servidor Django és capaç de generar una plana on es publiquen els mètodes del json rpc i una petita utilitat per comprovar-ne el funcionament. Semblant al WSDL però millor i tot.
Encara és prest per saber si Qooxdoo complirà totes les espectatives que hi tenc. Falta comprovar com es porta amb widgets complexos: taules, llistes, mescla de contingut web html amb el javascript generat i veure com es pot tractar l'autenticació i la seguretat. Per ara pareix que generar interfícies d'usuari potents és prou senzill i que la comunicació amb altres sistemes és possible, i ara per ara li veig moltes més possibilitat que opcions com Dojo i Extjs, sobretot perquè li veig una filossofia que m'agrada: la de tenir un sistema pensat per al desenvolupador i per al qui ha de mantenir l'aplicació.
Traducciones/Translations by apertium
1 comentari, 0 trackbacks (URL) , Tags: Python Django qooxdoo
Django 1.1
Escrit per Aaloy a 29 de July , 2009 a les 8:35 p.m.
Des de fa poquetes hores ja tenim la versió 1.1 de Django. Les novetats es poden trobar a l'anunci oficial de Django 1.1.
Per mi el més interessant són els canvis a l'ORM (les agregacions són una característica llargament esperada) i les millores a l'Admin, que es pot personalitzar sense fer tant esforç com abans.
Enhorabona als "core developers" i a tots els que feim feina amb Django. Tenim cada dia un bastiment més productiu i potent, on tot el que s'afegeix no és per mor del marketing o perquè fa "cool", sinó perquè realment serveix per a la feina.
Traducciones/Translations by apertium
1 comentari, 0 trackbacks (URL) , Tags: Python Django
Escalabilitat, multiprocessador i GIL
Escrit per Aaloy a 16 de July , 2009 a les 8:34 p.m.
Una de les dèries que tenim com a informàtics (o que hauríem de tenir) és la d'aprofitar el millor possible els recursos que tenim a la nostra disposició.
Això es tradueix algunes vegades en discussions de que si un llenguatge és millor que un altre en l'aprofitament de la màquina, i quan toca a Python, el tema estrella és el GIL, el mecanisme intern que fa servir Python per poder ser multi-fil. GIL fa que les aplicacions que fan un us intensiu dels fils no siguin tan òptimes com podrien ser (potser sí són més segures i més bones de programar, però això és una altra història) i que puguem pensar no facin tan bon us dels múltiples processadors com es podria suposar. En aquests casos el millor potser és llegir un article molt aclaridor, en lloc de començar a pegar destralades.
Tot i això, pareix que hi ha una confusió entre el que representa l'escalabilitat d'una aplicació i el nombre de processadors d'una màquina. En principi pareix el mateix, però realment no ho és.
La vertadera escalabilitat no la dóna el fet de que l'aplicació aprofiti al 100% els 4 o 8 processadors que pugui tenir el nostre servidor, l'escalabilitat la tenim quan aquesta mateixa aplicació pot executar-se damunt 8 màquines amb els processadors que tenguin. És a dir, que davant un problema que necessiti més potència de màquina, la solució no sigui posar una màquina amb més processadors, sinó posar més màquines.
Aqui ja no parlar d'aplicacions que executin fils, parlam d'aplicacions que executen processos, de comunicacions entre processos, de particionat de la nostra aplicació de manera que pugui distribuir-se.
Una de les maneres més senzilles que he trobat d'obtenir això és mitjançant els sistemes de missatgeria i de les coes de feina. En aquest cas tenim un o varis servidors que actuen de gestors de les coes de feina i una sèrie de processos que envien tasques a la cua per a ser realitzades, processos que realitzen les tasques i processos que consumeixen els resultats. El GIL no és un problema, el problema és pensar en com s'ha de fer l'aplicació, en com distribuir les càrregues entre els servidors, en definitiva, el problema és d'enginyeria de programari pur i dur. Passam de pensar en dues dimensions a pensar en n-dimensions.
Si hi ha una cosa que té bona Python és la poca distància que hi ha entre voler fer una cosa i tenir la capacitat de fer-la. Així doncs fer programes que facin servir les cues és realment trivial: posam un servidor, el beanstalkc per exemple, les llibreries Python que facin de client i ja ho tenim llest. Separar l'aplicació real per a que vagi en capes i establir un sistema integrat de control, això ja és una altra cosa :)
Quan parlam d'aplicacions web un sistema de coes a més pot fer-se servir per a augmentar l'escalabilitat de la nostra aplicació i donar un millor temps de resposta als nostres usuaris.
Imaginem per exemple una situació típica: la nostra web (feta amb Django, per suposat) quan acaba el procés de compra envia un e-mail a l'usuari amb la factura del que acaba de comprar.
Si no ens hem complicat la vida, tendrem que dins la mateixa vista que guarda les dades de la compra hem posat una cridada a la funció que genera el pdf amb la factura i la cridada a la funció que l'envia.
Encara que la factura es generi força ràpid, generar i enviar el pdf pot ser un problema si tenim molta càrrega, consumeix cicles de CPU que estam llevant als visitants de la nostra web.
En aquest cas podem tenir una maquina o vàries destinades a la generació i enviament de les factures. La nostra aplicació web sols envia a la cua (a una altra màquina o màquines) la petició de que s'ha de fer la factura, i els processos que tenim escoltant a la cua de treballs generaran i enviaran la factura.
Com que l'enviament del treball a la cua de treballs és pràcticament instantani, l'usuari té la sensació de que la web ha respost molt ràpidament. Com que tenim màquines dedicades per a la generació de les factures aquestes també es generen força aviat i s'envien. Mentre hem deixat el servidor (o servidors web) descarregats per atendre més peticions. Hem escalat!
És un exemple típic, com veis l'escalabilitat no s'ha aconseguit posant més màquines que fessin de servidors d'aplicacions Django o posant més processadors, sinó separant les tasques en màquines especialitzades. Si parlam de parsejar XML la cosa és encara més divertida, a l'article [High-performance XML parsing in Python with lxml] (http://www.ibm.com/developerworks/xml/library/x-hiperfparse/) de la web d'IBM i gairebé a les acaballes també ens dóna la pista: l'estratègia de dividir i conquerir; una altra vegada més pensar en com feim les coses.
Aquest és un apunt damunt escalabilita, Python i Django, però perfectament podríeu substituir Python pel vostre llenguatge de capçalera i Django pel vostre bastiment web preferit, Python fa fàcil provar totes aquestes coses, però el realment important és adonar-se de que es poden fer.
Traducciones/Translations by apertium
6 comentaris, 0 trackbacks (URL) , Tags: Python Django
Eclipse Galileo vs Netbeans Python (trunk) per Python i Django
Escrit per Aaloy a 05 de July , 2009 a les 11:42 a.m.
La publicació de la nova versió d'Eclipse, Galileo ha servir d'excusa per a tornar (al manco temporalment) a Eclipse com a entorn de desenvolupament per Python.
És la versió Galileo d'Eclipse millor que Netbeans? Doncs depèn, al cap i a la fi del que es tracta és de que l'IDE ens faci més productius, però a partir d'aquí ja és una qüestió de preferències personals.
Anem a veure les meves...
Facilitat d'instal·lació
La facilitat d'instal·lació és important perquè fa que puguis actualitzar de versió o posar un nou programador a fer feina en poc temps. La gent que fa feina amb PL em diu que necessita molt de temps per poder tenir l'entorn de desenvolupament llest, i com tots sabem temps són doblers.
Ambdós entorns són iguals de bons d'instal·lar. Ambdós tenen una arquitectura de plugins, així que la velocitat de posada en marxa depèn fonamentalment del nostre ampla de banda.
Si ens limitam a Python dir que la versió de Netbeans per Python ja duu el pluggin integrat i necessita davallar menys coses. De la mateixa manera no és necessiten pluggins addicionals al Netbeans per fer feina amb javascript, css o html, ja ve tot de sèrie.
Guanya Netbeans però de ben poc, ja que gràcies a projectes com Yoxo podem configurar-nos la nostra pròpia distribució d'Eclipse.
Portabilitat
Faig feina gairebé al 99% damunt Linux, però amb versions i386 i PPC. De tant en tant he de provar alguna cosa damunt Windows i per això vull que el meu entorn de desenvolupament pugui funcionar igual de bé en totes aquestes plataformes.
Aquí hi ha un guanyador clar: Netbeans. Funciona igual de bé a totes les plataformes. Eclipse dóna molts problemes al PPC i de fet aquesta plataforma no està soportada als repositoris oficials.
Suport per Python
La versió Python de Nebeans ja té el pluggin integrat. Eclipse necessita el pluggin PyDev. Ambdós pluggins són molt bons: permeten la utilització del virtualenv, tenen ressaltat de sintaxi, autocompletat, ajudes, plantilles, refactorització i creació de Unit Tests. Empat!
Suport per Django
Cap d'ells proporciona un suport específic per Django, encara que Netbeans ho té com a projecte. Tanmateix, però, el més important és que l'entorn permeti executar el python manage.py runserver --noreload en mode depuració.
Aquí Netbeans falla. El depurador està molt enfora del depurador d'Eclipse i Pydev, que et permet posar punts de ruptura on vulguis i té tot el que un necessita en depuració. Amb Netbeans no hi ha més remei que fer servir import pdb; pdb.set_trace() al codi i utilitzar el depurador de línia de comandes. És un punt de millora molt important per Netbeans, i si no us sentiu còmodes amb la depuració per línea de comandes llavors l'elecció clara és Eclipse.
Suport per CSS
Eclipse necessita el puggin d'Aptana per posar-se a nivell de Netbeans i al meu parer no ho aconsegueix del tot. Ambdós tenen ressaltat de sintaxis, autocompletat i ajudes, però Netbeans a més et pot presentar un exemple de com queden les coses. Útil en algunes ocasions per veure visualment que l'estil que estam modificant queda com volem o que és el que volem modificar. Netbeans guanya per poc.
Suport per Javascript
Una altra vegada més Eclipse necessita d'Aptana per posar-se a nivell de Netbeans. Netbeans més proporciona un mode de depuració de javascript basada amb Firebug que va força bé. Pareix que Eclipse també suporta quelcom semblant però no és tan inmediat com amb Netbeans. No és una opció molt important, però donat que estam parlant d'integració de les eines més habituals a l'IDE s'ha de tenir en compte. Netbeans guanya.
Control de temps i tasques
Ambdós entorns ens permeten gestionar llistes de tasques a fer i controlar el temps dedicat a cada tasca. Associar arxius a tasques i controlar automàticament quan hi estam fent feina i quant no. Això és fonamental pels qui factures a hores o senzillament volen dur un control dels projectes.
Nosaltres feim feina amb Trac i Eclipse gràcies al pluggin Mylyn permet connectar-se a un repositori Trac i gestionar-ne les tasques. Eclipse guanya!
Aprofitament de l'espai
Personalment m'agrada tenir una distribució on tengui a la vista l'arbre d'arxius, l'editor i la consola de tasques i missatges. Quan faig feina amb les dues pantalles de 20" puc posar l'IDE a una pantalla i el navegador a l'altra, però quan faig feina amb sols una pantalla l'aprofitament de l'espai de l'IDE fa que pugui, o no, col·locar-hot tot per a tenir una visualtizació més ràpida i ergonòmica.
Eclipse consumeix molt més espai que Netbeans. Es pot tunejar un poc, però la tendència és a desaprofitar pixels en menús, pipelles i demés. L'estructura de Netbeans per mí és molt més elegant i amb un aprofitament d'espai gairebé òptim. Com a IDE per al portàtil: Netbeans.
Integració amb SCM
La integració amb el sistemes de control de versions és prou bona a ambdós entorns. En la nova versió la integració del pluggin Subversive és excel·lent a Eclipse i l'assistent gràfic en el maneig de branques de Netbeans és simplement genial.
En les operacions del dia a dia Eclipse guanya. Té una opció que et permet veure els canvis entrant i sortint (això també ho fa Netbeans) però a diferència de Netbeans la interfície d'usuari està molt més orientada a la usabilitat i és trivial llevar arxius, marcar-los com a no integrables, veure'n les diferències abans d'integrar, etc.
La usabilitat de Netbeans és força dolenta, de fet és molt més còmode anar per línia de comandes. Guanyador i amb molt avantatge: Eclipse.
Revisió de canvis
Netbeans ens permet mostrar quins canvis hem fet a l'arxiu que estam editant i manté un control local de versions. Eclipse també manté aquest control local, però la usabilitat és inferior.
A l'hora de mostrar diferències Netbeans manté el ressaltat de sintaxi, Eclipse no. Per mi el més útil és el control local i aquí Netbeans és el millor.
Plantilles
Ambdós IDEs ens permeten crear i gestionar les nostres pròpies plantilles de codi i ho fan força bé. Empat!
Execució de tests unitaris
Ambdós sistemes ho permeten, però com passa amb el control de versions, el d'Eclipse és molt més usable. Guanyador per poc: Eclipse.
Refactorització
Els dos entorns suporten la refactorització de códi. Empat!
Eines d'edició
Ambdós entorns ens permeten fer cerques a tot el projecte, fer servir expressions regulars, substitucions, ... Els dos editors són força avançats i més que suficients per a les necessitats d'edició de codi. Empat!
Afegitons
Eclipse des del principi ha fet de la possibilitat d'extendre l'entorn mitjançant pluggins una virtut. Netbeans s'hi ha incorporat més tard i això es nota. La quantitat d'afegitons per Eclipse esborrona, per Netbeans cada cop n'hi ha més i millors però encara Eclipse n'és un clar guanyador.
L'aposta per Python i Django
Eclipse no té una orientació clara cap a Python, però gràcies a PyDev i a la facilitat que té Eclipse per a integrar pluggins s'ha convertit en un entorn molt potent per a la programació.
Netbeans en canvi té un build sols per Python, ple suport i al roadmap hi ha la intenció de suportar Django: creació de projectes, plantilles, etc. L'aposta per Python a ca'n Netbeans pareix molt més clara que a Eclipse, encara que en aquests moments i com a regla general, actualment Eclipse proporciona molta més funcionalitat i integració que Netbeans.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python Django
Enumerate: indexant les llistes en Python
Escrit per Aaloy a 21 de June , 2009 a les 11:21 a.m.
Quan feim feina amb llistes de tant en tant en sorgeix la necessitat de fer feina amb l'index de la llista en lloc (o a més) de l'element de la llista en sí.
Sovint ens podem trobar fent coses com
1 2 3 4 5 | x = ['a','b','c'] i = 0 for item in x: i +=1 print i, item |
Davant aquest tipus de problemes, pensau que el més habitual és que el propi llenguatge ja ho tengui resolt, de la mateixa manera que els problemes més habituals de la programació web estan resolts per Django.
El nostre problema es redueix a fer servir enumerate. Aquesta funció agafa un iterador (una llista per exemple) i ens retorna un nou iterador, els elements del qual són una tupla composta pel comptador (l'índex) i l'element de l'iterador inicial que li passam com a paràmetre.
enumerate pot agafar com a paràmetre un nombre que serà el valor inicial de la seqüència (per defecte zero). La seva sintaxi és doncs enumerate(iterable, start=0)
Amb això podem escriure el codi anterior com
1 2 3 | x = ['a','b','c'] for i, item in enumerate(x): print i, item |
o sí volem comptar a partir d'1
1 2 3 | x = ['a','b','c'] for i, item in enumerate(x, 1): print i, item |
El nom a més és prou descriptiu de la funcionalitat que fa, amb la qual cosa el codi ens queda fins i tot millor documentat.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python Django
Django: Guia d'aprenentatge
Escrit per Aaloy a 07 de June , 2009 a les 4:49 p.m.
La pregunta a la que vull intentar respondre en aquest article, és la que fa força gent que vol canviar la manera en que fa aplicacions web i com que ha sentit parlar molt bé de Django, s'atraca a aquest bastiment amb l'esperança de poder millorar la seva productivitat, és a dir: què he de saber per començar a fer webs amb Django?
Primer de tot em de saber què és Django. Django és un bastiment, és a dir, tot un conjunt de llibreries que interactuen entre sí i que estan orientades a fer i mantenir llocs i aplicacions web.
Primera cosa, doncs, Django no és un llenguatge de programació. Per a fer servir Django es necesita conèixer el llenguatge de programació amb el que està creat i aquest llenguatge no és ni més ni manco que Python.
Segona cosa: Com a bastiment que és Django requereix que les coses es facin d'una determinada manera, és el que anomena modle MVT (Model Vista Template), però al mateix temps ens està dient que per sí sol Django no ens construirà la nostra aplicació. Hi haurem de fer feina, segurament aquesta feina serà més ràpida i productiva, però no hi ha solucions màgiques.
Prerequisits
- Se suposa que sabeu programar en algun llenguatge d'alt nivell.
- Se suposa que teniu coneixements d'HTML i CSS
- Se suposa que teniu coneixements del que és una base de dades relacional i d'SQL
- Se suposa que saber fer anar la línia de comandes
Si no compliu aquests quatre requisits convendria replantejar-se el tema. Segurament trobareu que Django no és l'eina màgica que havíeu suposat.
En aquests temps de crisi costa molt dir que no als clients i una vegada emmerdats anar cercant l'eina màgica que ens tregui del problema. Per molt bona que sigui l'eina sempre hi haurà una sèrie de requisits, si no els compliu, millor cercau una altra cosa (potser una altra feina?) o anau invertint en la vostra formació de base.
Supòs que tots els que llegiu això compliu de sobra aquests requisits i m'estic passant de prudent i tiquis-miquis, però tenc una anècdota molt recent: l'empresa per la que treball habitualment va demanar un pressupost a una empresa externa. A aquesta empresa (no diré noms, però no és de Mallorca) se li va demanar que el pressupòs contemplàs que el llenguatge de programació triat per fer l'aplicació fos Python+Django, Java J2EE (amb Hibernate, Spring i JSP) i que en tot cas podien presentar la proposta per PHP. La proposta Java feia servir CakePHP i Zend i cap referència a cap tecnologia Java. La proposta PHP cap referència a versió de PHP. Imaginau quina impressió dóna el pressupost! Per acabar-ho de rematar la primera cosa que deia és que s'havia de fer l'anàlisi de requeriments. Què s'ha pressupostat doncs? Entenc que amb la crisi tothom està arreplegant tot el que pot, però tot té un límit!
Així doncs, per a començar, suposarem que ja teniu un cert nivell informàtico-programador i que no és la primera vegada que sentiu parlar de l'HTML i heu picat planes web a mà. L'SQL potser inicialment no serà tant necessari, però si realment volem arribar a fer aplicacions web mantenibles és imprescindible saber-ne i conèixer al manco els fonaments de les bases de dades relacionals.
Bé, ja ho tenim clar, i si heu arribat fins aquí ara estareu esperant que us digui cap on heu de tirar, què és el que s'ha d'aprendre i amb quin ordre per fer que la corba d'aprenentatge sigui el més suau possible. Som-hi doncs!
El bàsic de Python
Python és un llenguatge de propòsit general, molt net i estructurat. Es poden fer tant aplicacions de consola, aplicacions web o aplicacions gràfiques, el que vulguem. El que propòs aquí es el mínim que convé saber per poder fer webs quan abans millor i anar aprenent el llenguatge i les seves llibreries associades així com ho necessitem.
Una guia molt senzilla és la que tenim a Python para todos de Raúl González Duque, i que ens servirà com a referència d'estudi i com no el tutorial de Python. Què hem de saber en aquesta etapa?
La consola
- Utilitzar Python en mode consola: Python com a calculadora
- Instal·lació i execució d'iPython
El llenguatge
Hem de perdre la por a fer feina amb una consola de comandaments. La consola ens permetrà experimentar ràpidament amb el llenguatge, ens n'adonarem del que representa fer feina amb un llenguatge interpretat i fer fer-ho am iPython a més ens permetrà veure algunes de les possibilitat d'aquesta consola (que no oblidem la utilitza Django si està instal·lada).
- Creació del "Hola Món". Establim les regles de tabulació (tabulació a 4 espais, UTF-8 i format Unix pels arxius és la meva elecció.)
- Tipus bàsics: experimentació amb el intèrpret i l'editor. Nombres, cadenes, boolenas, llistes, tuples i diccionaris.
- Sentències de control:
if,for,pass,breakicontinue - Dates a Python.
- Creació de funcions bàsiques. Paràmetres per nom, valors per defecte.
- Documentació i comentaris
Amb això ja tindrem les nocions bàsiques del llenguatge. Encara no hem entrat en tota la potència de Python però si hem programat en una altra llenguatge ja tindrem en ment un bon anàlisi comparatiu. Segurament ja estareu pensant com refer alguns programent en Python.
- Orientació a objectes bàsica.
- Les funcions són també objectes. La funció lambda
- Els paquets.
Amb un poc de sort ja sabreu què és la orientació a objectes, si nó és un bon moment per aprendre'n. L'objectiu és adonar-nos de que tot en Python és un objecte i com s'estructura el codi en classes, mòduls i paquets.
- Programació funcional: fonamental veure la comprensió de llistes.
- Ordenació de llistes.
- Creació Manipulació de fitxers, utilització de les llibreries
osysys - Les excepcions.
Amb això ja tindrem gairebé el 80% del que necessitarem per fer una aplicació de consola, però no oblidem que a més nosaltres volem fer aplicacions web i a més amb Django, així que afegirem un parell de coses més:
- Expresions regulars bàsiques amb Python. L'eina Kodos.
- El mòdul Sqlite3 i el plugin de Firefox per a gestionar les bases de dades Sqlite.
- l'
easy_install. Hem de saber què és i com utilitzar-lo per a instalar noves llibreries. - Batteries included. Convé saber què significa aquest concepte i veure, al manco llegir, quines són les principals llibreries que Python inclou i què fan.
Amb això ja ens estam orientant cap a la web i Django. Les expressions regulars les farem servir sovint a Django a l'hore de mapejar urls amb les funcions Python corresponent. El mòdul sqlite ens permetrà veure el que és la API d'accés a base de dades de Python, familiaritzar-nos amb sqlite i si no ho havíem fet ja, començar a instal·lar els primers plugins de Firefox. Perquè tothom té Firefox per a desenvolupar webs, no?
Django
Podem començar a fer aplicacions web una vegada coneguem i ens sentim còmodes amb el llenguatge. El temps dedicat a Python no és per res temps perdut, ben al contrari. Feis exercicis, creau scripts, llegiu codi, l'important és poder llegir Python i que les instruccions surtin de manera natural.
- Instalau Django des del subversion
- Feis el tutorial de Django.
No està pensat per ser un manual de millors pràctiques sinó per mostrar el principal del bastiment i tenir alguna cosa repetible, una base comú.
- Mirau appfusedjango, el subprojecte
project. Està fet per a crear nous projectes pel mètode de copiar i aferrar.
Els models
- Creació de models: l'ORM de Django.
- Utilització de la consola per a introduïr dades als models
- Utilització del manager de Django per afegir dades.
- Execució de consultes fent servir l'ORM
En les aplicacions web passarem força temps manipulant dades, bé des de la web o bé directament amb scripts i la consola. Convé que no hi hagi por.
Les plantilles
- Creació de planes estàtiques
És un primer exercici. Consisteix en agafar un grapat de planes estàtiques i convertir-les en una aplicació Django utilitzant el direct_to_template. Això
ens ha de permetre veure com, sense més complicacions podem fer planes a la manera tradicional (i inefectiva).
- Les plantilles de Django: definició i concepte d'herència.
- Filtres
- Tags
- Refer les planes estàtiques anteriors fent servir l'herència de plantilles.
Aquí començarem a veure les possibilitats que té Django respecte de la manera més tradicional de fer les coses. Veurem que fer webs amb blocs i pensant en diferències és molt productiu.
El view.py i url.py
- Veure com les urls mapegen contra funcions Python
- Utilització de les plantilles
- Les expressions regulars i les urls.
- HttpResponse, render_to_template , redirect
Ens n'hem d'adonar que no hi ha màgia, que tot és codi Python que envolcalla al protocol HTTP.
Formularis
- Creació de formularis.
- Renderització de formularis
- Formularis lligats a dades
- Validació i control d'errors.
- Pujar arxius i imatges.
- L'autenticació
Dedicau el temps que sigui necessari als formularis. De ben segur en fareu molts al llarg del cicle de vida d'una aplicació web. Django és molt elegant en la seva utilització.
Quan es veuen els formularis m'agrada passar també per l'autenticació, ja que en aquest punt ja es té tot el necessari i consider que l'aspecte de la seguretat s'ha de tractar tot d'una que es pot.
Reflexió
No sé ben bé com anomenar aquesta etapa, però convé que dediqueu alguns dies a fer una aplicació web des de zero. Pensau en alguna que es us agradaria fer i vegeu-ne la seva viabilitat. Reduïu-ne l'abast si és necessari, però intentau fer una aplicació web completa.
L'objectiu és adonar-nos del que sabem, del que no sabem i del que no sabíem que no sabíem.
Django i Javascript
- Json i Django
- Exemple de jQuery (o la llibreria que utilitzeu) i com lliga amb les urls y views de Django.
No sols d'HTML viu l'home i cada cop les planes web tenen més javascript. Django és agnòstic en el que fa a la llibreria a utilitzar, però sigui com sigui fa que sigui realment fàcil interactuar amb llibreries javascript com jQuery, extjs o Dojo.
Fent les webs escalables
- Internacionalització
- Els principals middlewars.
- Sistemes de cachés
- Context processors
- Creació de tags pròpies
Aquí ens n'adonarem de les respostes que dóna Django als problemes reals quan la nostra web passa de ser una idea a estar en producció i té prou visites. Hem de veure a més com podem interactuar amb les peticions HTTP i amb la informació que passam a les plantilles.
Reutilització
- Convé adonar-se de com Django permet reutilitzar codi, de l'estructuració del projecte en aplicacions i d'aquestes en mòduls PYthon.
- Repassar els principals settings.
- Repassar les aplicacions que ja venen incorporades al bastiment: e-mail, sessions, paginació, signals, sitemaps i sites.
- Algunes aplicacions interessants: django-photologuer, django-page-cms, django-rosetta, django-command-extensions
Reflexió 2
Tornau a fer l'aplicació anterior incorporant javascript, internacionalització, cachés i tags fets ad-hoc. Mirau com queda el codi i com queda l'aplicació.
Arribats a aquest punt ja estau llets per anar agafant cada vegada més coneixements. No oblideu que aquests han de venir tant des de la part Python com de Django. Quan una cosa no vegeu com es pot fer amb Django cercau en el propil llenguatge. Si és un problema comú segur que està solucionat en el propi bastiment, i si no ho està vol dir que ja té solució a nivell de llenguatge de programació.
Això és tot, esper que us servesqui de guia i us animi a fer feina en aquest bastiment. Recordau, però que no hi ha bales de plata i que tot requereix esforç i dedicació.
Traducciones/Translations by apertium
3 comentaris, 0 trackbacks (URL) , Tags: Python Django
Django i python: orientat a la feina
Escrit per Aaloy a 03 de June , 2009 a les 6:36 p.m.
Avui, mentre explicava a la gent de l'equip web un grapat d'optimitzacions que podem fer per fer que les nostres aplicacions siguin més ràpides i actualitzables, al mateix temps pensava que en la potència que ens està donant Python i Django gràcies a la seva orientació cap a fer les coses com s'han de fer.
La comparació amb Java, l'altre llenguatge que feim servir, no pot deixar d'estar present, i llevat d'excepcions (poques) he de dir que la combinació Python i Django en surt sempre afavorida davant de Java.
Django està molt orientat a la web, però no de qualsevol manera, està orientat a fer webs que s'han de mantenir i que han d'escalar. Per això veus que és gairebé trivial fer coses que en altres plataformes resulten força costoses: qui no recorda el que s'ha de fer per fer un redirect amb Struts, per exemple?, o la complexitat que té validar formularis tant amb Struts com amb Spring?.
Django està orientat a fer aplicacions pel món real, això vol dir: que surtin ràpides, puguin sofrir moltes modificacions al llarg del seu cicle de vida i que es pugin actualitzar també molt ràpidament.
El bastiment segueix de molt aprop la filosofia de Python, la de mantenir les coses legibles i simples. Hi ha d'haver sempre una manera obvia de fer les coses, i quan fas feina amb Django veus que els 90% dels problemes que et planteja una aplicació web tenen resposta directa. La resta poden dur un poc més de feina, que normalment vol dir fer herència d'alguna classe.
Una de les darreres aplicacions en les que he pogut comparar Java i Python ha estat una aplicació que agafa XML, el manipula i el posa dins una base de dades. L'aplicació original, feta amb Java+Spring+Hibernate, va dur setmanes de feina, mesos si contam el manteniment posterior. Fer el mateix amb Python (lxml+sqlalchemy) ha duit menys de 4 dies-home de feina.
Posar l'aplicació Java en producció també va ser un poc malson per mor de les dependències entre les llibreries. Posar-la en Python dins un virtualenv és pràcticament immediat.
Tampoc ha resistit la comparació el manteniment i la correcció d'errors. El temps que passa per localitzar l'error i fer l'actualització en Python és mínim, en Java multiplicant per 10 o per 20 aquest temps.
Ens queda un tema: el rendiment. Com moltes vegades he dit per aquí el rendiment basta que sigui "prou bo", és a dir, per l'aplicació que estam parlant partíem d'un temps de càrrega d'entre 4 hores en les primeres versions Java, a 30 minuts a les darreres versions amb multi-fil. Amb màquines amb 8 Gb de RAM i menjant-se la màquina tant amb memòria com amb processador.
La versió Python també es feta amb multi-fil, on el nombre de fils és parametritzable, amb pool de connexions i demés. Sols que escrit amb un 10% de les línies de codi. El temps? Doncs 6 minuts i mig. Consum de memòria: mínim, ús de la CPU: intensiu però sense deixar torrada la màquina.
Python està orientat a que les coses es facin i es mantenguin. Per algunes tasques concretes potser no serà la millor solució, però cada vegada estic més convençut que és el primer que s'ha de provar. Si no va prou bé, el prototip ens haurà servir per a conèixer millor l'abast del problema sense haver-hi invertit molt de temps, i sempre som a temps d'optimitzar alguna secció del codi amb C, de maneres per utilitzar codi C (o C++) o bé d'escriure codi intermig que es transformi en codi C compilable n'hi ha força. Al wiki de Cpython (una de les eines que ens permet fer això) n'hi ha un bon grapat.
Traducciones/Translations by apertium
5 comentaris, 0 trackbacks (URL) , Tags: Python Django
Django, imatges i Imagekit
Escrit per Aaloy a 23 de May , 2009 a les 4:46 p.m.
Django Imagekit és una llibreria creada per Justin Driscoll que ens permet crear miniatures i/o distints tamanys d'imatges a partir de la imatge original, i que s'integra molt bé amb Django. És una llibreria més senzilla que la de django-photologue ja que no té tota la funcionalitat per a crear gal·leries fotogràfiques.
El tutorial per a fer-la anar està força bé, però aprofitaré la benentesa per a fer cinc cèntims de com podem pujar una imatge al nostre site amb Django i presentar-la de nou.
El codi font de l'exemple complet és a appfusedjango.
El model
Per començar definim el model:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | from django.db import models from imagekit.models import ImageModel from django.db import models from imagekit.specs import ImageSpec class Photo (ImageModel): image = models.ImageField(upload_to='photos') comments = models.TextField() num_views = models.PositiveIntegerField(editable = False, default = 0) class IKOptions: spec_module = 'sample.specs' cache_dir = 'photos/cache' image_field = 'image' save_count_as = 'num_views' def thumb(self): if self.image: return '<img src="%s">' % self.thumbnail.url else: return "" thumb.allow_tags = True thumb.short_description = 'Foto' |
En aquest cas es tracta d'un model molt senzill, guardam la imatge image al directori photos i posarem dins la base de dades tant la referència del fitxer (això és important, dins la base de dades no és guarda la imatges sinó sols la metadada) i el comentari.
El camp num_views ens pots servir per anar guardar la quantitat de vegades que s'ha vist la imatge i és utilitzat si volem per la llibreria d'Imagekit.
La part interessant és a la classe IKOptions. Aquesta defineix quin tractament se li donarà a la imatge, on s'enmagatzemaran les miniatures i a quin camp es fa referència.
spec_moduleÉs el mòdul d'ImageKit que es farà servir i que defineix els tamanys possibles. D'aquí una estona el veurem amb detall. En el nostre cas el modul es diuspecs.cache_dir: guardarem els distints tamanys generats aphotos/cacheimage_field: Les metadaes son pel campimagedel model.
El mètode thumb ens serviex per poder posar la miniatura dins el llistat de l'admin.
Els tamanys
Per definir els tamanys Imagekit distingeix entre el que és la visualització de la imatge i les manipulacions que s'hi fan. La imatge original necessita passar per uns filtres que Imagekit anomena processors. Una imatge pot generar-se aplicant un o més d'aquests filtres.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | from imagekit.specs import ImageSpec from imagekit import processors # define the thumnail processor class ResizeThumb(processors.Resize): width = 100 height = 75 crop = True class ResizeDisplay(processors.Resize): width = 600 class ResizeBig(processors.Resize): width = 800 # define your spec class Thumbnail(ImageSpec): pre_cache = True processors = [ResizeThumb,] class Display(ImageSpec): processors = [ResizeDisplay,] class Big(ImageSpec): processors = [ResizeBig,] |
A l'exemple sols faig servir un tipus de processor el de Resize per a redimensonar la imatge als tamanys que farem servir.
Pujam una imatge
Per pujar una imatge necessitam definir un formulari, el mètode que tractarà aquest formulari i les urls que farem servir, així com les plantilles que es mostraran.
Les urls
Aquesta és la part senzilla.
1 2 3 4 5 6 7 8 9 | from django.conf.urls.defaults import * from django.conf import settings from django.contrib import admin admin.autodiscover() urlpatterns = patterns('', url(r'^$','sample.views.index', name="main-page"), url(r'^display/(?P<id>\d+)/$','sample.views.display', name="display-image"), .... |
Definim una url per l'index que identificarem per nom main-page i que serà tractada al mètode index del mòdul views del nostre paquet sample.
I una altra ulr que ens permetrà visualitzar la imatge a partir del seu identificador. Anomenam a aquesta url display-image, original que és un...
El formulari
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # -*- coding: UTF-8 -*- from django import forms from PIL import Image class AttachmentForm(forms.Form): """Form for the attachment sample. Added a simple validation to accept only png files checking for 'image/png' in the content_type of the file""" image = forms.FileField(help_text="add a png or jpg file") comments = forms.CharField(widget= forms.Textarea, help_text="describe the image") def clean(self): "Validate the entire form" cleaned = self.cleaned_data try: file = cleaned['image'] except Exception, e: # perhaps this is not a file raise forms.ValidationError("Not valid file: %s" % e) if not file.content_type.lower() in ["image/jpeg", "image/png", "image/jpg"]: raise forms.ValidationError("Just jpg or png files please") im = Image.open(file) if not im.format in ['JPEG','PNG']: raise forms.ValidationError("Just jpg or png files please") return cleaned |
El formulari com es pot veure és d'allò més normalet, definim un camp per la imatge i un camp per als comentaris.
La part "nova" està en la validació. No ens podem fiar del que ens diu la gent que puja, així que le que farem és comprovar que el mime type es correspon amb un format vàlid, i com que fins i tot això es pot manipular, farem una comprovació addicional amb PIL per a comprovar que la imatge és el que diu ser. Aquesta comprovació dependrà del vostre nivell de paranoia.
Tractant la imatge
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | from models import Photo from django.http import HttpResponseRedirect from django.shortcuts import render_to_response from forms import AttachmentForm def index(request): "Obtains the attachment and saves it to the disk" if request.method == 'POST': form = AttachmentForm(request.POST, request.FILES) if form.is_valid(): f = form.cleaned_data['image'] foto = Photo() foto.image.save(f.name, f) foto.comments = form.cleaned_data['comments'] foto.save() return HttpResponseRedirect('/') else: form = AttachmentForm() fotos = Photo.objects.all() return render_to_response('index.html', {'form':form, 'fotos': fotos}) |
Per a tractar arxius i imatges la part delicada és recordar que hem de passar la informació al formulari afegint el request.FILES i pensar a posar al formulari enctype="multipart/form-data"
A més d'això hem de guardar dues vegades: una per la imatge, que guardarà el contingut dins el sistema de fitxers, i una altra per la resta del model i les metadades de la imatge. Per això tenim un foto.image.save(f.nam, f) guarda la imatge al sistema de fitxers.
Mostrar una imatge és prou senzill
1 2 3 | def display(request, id): foto = Photo.objects.get(pk=id) return render_to_response('image.html', {'foto': foto}) |
Mostrant les imatges
Al template hi passam objectes del tipus Photo, que recordem tenen tota la fontaneria del ImageKit.
Això vol dir que a més de la imatge original, puc fer servir els formats que he definit a specs: Thumbnail, Display, Big.
Per utilitzar-los en la nostra plana sols hi hem de fer referència:
1 2 3 | <li><img src="{{foto.thumbnail.url}}" /></li> <li><img src="{{foto.display.url}}" /></li> <li><img src="{{foto.big.url}}" /></li> |
com podem veure sols és cosa de fer referència al tamny definit i treure'n el que ens interessa, en el nostre cas la url per a mostrar la imatge.
Per darrera ImageKit se n'ha encarregat de fer les transformacions i guardar la imatge a la caché, de manera que la feina pesada de generació dels distints tamnays sols se fa un cop.
A partir d'aquí ens podem comlicar tant com voguem, per exemple:
- Al mètode clean fer que no es puguin pujar imatges de més d'un tamany.
- Reescriure el mètode save del model per a que no es guardi la imatge original sinó una altra imatges ja reduïda.
- Escriure més processors per fer més manipulacions a les imatges.
- etc. etc.
Però el és segur és que amb això que us he contat tingueu el 90% dels casos solucionats.
Nota: Oscar, esper que això et servesqui ;)
Traducciones/Translations by apertium
3 comentaris, 0 trackbacks (URL) , Tags: Python Django
Django vs PHP frameworks
Escrit per Aaloy a 10 de May , 2009 a les 6:36 p.m.
Llegint llegint he anat a parar a una plana que compara els principals bastiments (frameworks) PHP entre sí per demostrar com n'és de ràpid el KumbiaPHP comparat amb els altres.
Com que el codi utilitzat per les proves està disponible, doncs he vist que era un simple hello world, així que he creat un projecte hello_world a appfusedjango per poder comparar amb Django.
Disclaimer: La velocitat d'execució no ho és tot. Segur segur, que fet en x ben optimitzat l'aplicació y és més ràpida per aquesta prova. Això no és per veure qui la té més llarga, sols intent comparar coses més o manco semblants per saber on estam. Disclaimer 2: Qui en sap d'aquest tipus de proves és la gent que es dedica més a sistemes, en Bernat o en Guillem, per exemple :)
Amb què he fet les proves?
- La màquina es un PPC 64 de 2 MHz amb 1 Gb de RAM utilitzat Ubuntu 9.1 i Gnome com a Desktop. És a dir, no he fet servir un servidor i hi ha moltes coses executant-se.
- Python 2.5.2 (r252:60911, Jul 31 2008, 17:33:15) [GCC 4.2.3 (Ubuntu 4.2.3-2ubuntu7)] on linux2
- Com que em feia peresa muntar i configurar l'Apache he fet servir un servidor fet amb Django, el CherryPy, concretament el mòdul WSGI que podeu trobar al Django-Cerise sense executar-ho amb mode daemon per tenir major facilitat de modificar la quantitat de threads.
- La versió de Django és la trunk
- Per a les proves finals he optimitzat l'aplicació llevant tot el codi de depuració i middlewares que no es feien servir com el del la compressió gzip.
L'aplicació
L'aplicació no té cachés (tot a dummy i sense per-site-cache) i he fet que la plana en generar-se passi per la vista per a que es faci tot el recorregut MVT.
Els resultats:
executam ab -c 10 -t 60 http://localhost:8088/ cada vegada:
- Aplicació amb codi extra, servidor amb 10 threads 277 req/s
- Aplicació amb codi extra, servidor amb 3 threads 285 req/s
- Aplicació amb codi extra, servidor amb 5 threads 285 req/s
- Aplicació optimitzada, servidor amb 5 threads 334 req/s
- Aplicació optimitzada, servidor amb 3 threads 331 req/s
KumbiaPHP, el més ràpid de la comparativa PHP treu 34 req/s, casualitat? He fet alguna cosa malament? Potser, però no sóc el primer, hi ha gent que també ha notat un fort augment del rendiment en passar de PHP a Django.
I una de les proves:
ab -c 10 -t 60 http://localhost:8088/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient)
Completed 5000 requests
Completed 10000 requests
Completed 15000 requests
Completed 20000 requests
Finished 20009 requests
Server Software: CherryPy/3.0.3
Server Hostname: localhost
Server Port: 8088
Document Path: /
Document Length: 266 bytes
Concurrency Level: 10
Time taken for tests: 60.003 seconds
Complete requests: 20009
Failed requests: 0
Write errors: 0
Total transferred: 7723474 bytes
HTML transferred: 5322394 bytes
Requests per second: 333.47 [#/sec] (mean)
Time per request: 29.988 [ms] (mean)
Time per request: 2.999 [ms] (mean, across all concurrent requests)
Transfer rate: 125.70 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 2 82.1 0 3001
Processing: 4 27 41.7 24 2295
Waiting: 0 25 41.5 21 2291
Total: 5 30 92.1 24 3038
Percentage of the requests served within a certain time (ms)
50% 24
66% 28
75% 30
80% 32
90% 37
95% 43
98% 50
99% 59
100% 3038 (longest request)
(development)aaloy@G5:/tmp/djangocerise-master/src$ ab -c 10 -t 60 http://localhost:8088/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient)
Completed 5000 requests
Completed 10000 requests
Completed 15000 requests
Finished 19863 requests
Server Software: CherryPy/3.0.3
Server Hostname: localhost
Server Port: 8088
Document Path: /
Document Length: 266 bytes
Concurrency Level: 10
Time taken for tests: 60.006 seconds
Complete requests: 19863
Failed requests: 0
Write errors: 0
Total transferred: 7667358 bytes
HTML transferred: 5283558 bytes
Requests per second: 331.02 [#/sec] (mean)
Time per request: 30.210 [ms] (mean)
Time per request: 3.021 [ms] (mean, across all concurrent requests)
Transfer rate: 124.78 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.1 0 3
Processing: 12 30 9.0 29 361
Waiting: 10 28 8.7 27 361
Total: 12 30 9.1 29 362
Percentage of the requests served within a certain time (ms)
50% 29
66% 31
75% 33
80% 34
90% 37
95% 40
98% 44
99% 47
100% 362 (longest request)
Traducciones/Translations by apertium
6 comentaris, 0 trackbacks (URL) , Tags: Python Django
nose, per testejadors amb mala memòria
Escrit per Aaloy a 10 de May , 2009 a les 10:42 a.m.
Supòs que ja ningú dubta de la importància dels test unitaris a l'hora de programar. Els tests ens permeten provar que el que feim és correcte i repetir-ho tantes vegades com volguem i de manera controlada.
Els tests són una part important dels mecanismes de refactorització d'aplicacions, ja que ens asseguren que l'aplicació funciona de la mateixa manera abans i després de refactoritzar.
Els test, però, tenen un problema, fins ara els test unitaris s'han d'escriure d'una determinada manera, recordar les llibreries que has d'importar, com fer un testsuite. Per mi això significa anar a la documentació del pyUnit cada vegada o copiar un test anterior. És el que té dedicar-se a gestionar projectes, que no pots tenir al cap coses que sols fas servir de tant en tant, ja que sols dediques una quantitat mínima d'hores a programar.
Davant aquesta necessitat de fer tests sense tenir que preocupar-nos de la fontaneria intrínseca del pyUnit una de les millors opcions que hi ha és la llibreria nose. Vull dir, si sé que nose és perfecte per la feina (acudit fàcil).
Per fer un test típic basta recordar el següent:
- la sintaxis dels
assertde Python:assert condicio, missatge. - que gairebé qualsevol funció o classes que contengui
testoTestseparat amb quió baix és una funció testejable. - Que un test falla quan l'
assertfalla - Que fent un
nosetest -v nomexecutarem els tests en mode verbose del paquet o funció que li indiquem
La documentació és molt més àmplia, indica quan capturar la sortida, com fer l'equivalent al setup i al teardown dels pyUnit, capturar excepcions, etc. Però el 80% de vegades aquestes quatre coses que indic seran més que suficients.
La llibreria nose ens permet escriure els tests de la manera que estam tots acostumats quan escrivim codi per provar una funció, en nivell de formalització i cerimònia comparat amb els unittests clàssics és mínima, i per tant afavoreix que poguem convertir el codi de proves informal a codi per a la realització de test unitaris amb tant sols reanomenar la classe o funció que hem escrit, i moltes vegades ni tan sols això, ja que, no sé vosaltres, però jo ja tenia la mania de anomenar test a les funcions de prova :)
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python
Custom management commands
Escrit per Aaloy a 09 de May , 2009 a les 1:03 a.m.
Si heu fet al manco el tutorial de Django haureu fet servir per exemple el típic
python manage.py runserver
per a iniciar el servidor. A partir de la versió 1.0 de Django podem fer servir una sintaxi semblant per crear comandaments lligats a la nostra aplicació i que s'executin també d'aquesta manera.
Podem crear comandaments per fer qualsevol cosa, de fet es que acaba fent és executar un script de Python. Així doncs, ens podríem demanar quina avantatja hi ha en fer-ho així, vàries:
- No necessitam definir cap variable d'entorn per dir quin settings hem de fer servir, l'script manage.py ja se n'encarrega.
- El comandament quedarà lligat a l'aplicació. Per tant podem crear comandaments que depenguin d'una aplicació concreta i que la complementin.
- Podem accedir a l'ajuda del comandament si l'hem definida. Permet a l'usuari saber com ha de fer servir la comanda.
Podem crear tres tipus de comandament a mida, que trobam definits dins django.core.management.base
-
Comandaments que hereten de
AppCommandi que poden prendre com a paràmetre una llista d'aplicacions Django. -
Comandaments que hereten de
LabelCommandque poden prendre com a argument qualsevol cadena de text. -
Comandaments que hereten de
NoArgsCommandi que no prenen paràmetres.
Si anau a la documentació oficial de Django veureu que el que hi ha és més aviat poc. Potser perquè quan ja saps com és fa pareix tan fàcil que potser no mereix l'esforç. Tot i això, crec que és una opció prou útil i que hauria de tenir més importància a la documentació.
Afortunadament hi ha al manco dos articles prou bons que ens ajuden amb exemples a treure partit d'aquesta funcionalitat. Si anam al codi font comprovarem que tot està força documentat, però la realitat és que encara que a partir de la versió 1 fer aquests tipus de coses s'ha convertit en trivial, en versions anteriors no ho era.
Aquest apunt té per objectius fer publicitat d'aquesta funcionalitat, podeu trobar més informació al codi font de Django i als següents apunts:
i exemples tant al codi font de Django com a django-extensions .
Fes-hi una ullada, després de tot, fer un hello world d'aquesta manera és prou senzill:
1 2 3 4 5 6 | from django.core.management.base import NoArgsCommand class Command(NoAgrsCommand): help ="prints hello world" def handle_app(self, app, **options): print "Hello world" |
Per provar-ho creau un paquet python anomenat management dins la vostra aplicació Django, i dins aquest paquet un altre anomenat commands. Dins aquest hi posaríem els nostres scripts. Per exemple si la nostra aplicació es diu uep i volem crear un comandament que es cridi com python manage.py hello hauríem de crear una estructura com:
uep/
__init__.py
models.py
management/
__init__.py
commands/
___init__.py
hello.py
Els noms dels comandament poden col·lisionar, així que o bé tenim noms prou especials o bé convé prefixar-los amb el nom de la nostra aplicació per tal de tenir una oportunitat més.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python Django
Visor de logs amb Django
Escrit per Aaloy a 22 de April , 2009 a les 8:53 p.m.
L'altra dia em vaig trobar amb la necessitat de mostrar els logs de l'aplicació a la plana web que estava desenvolupant.
Per anar bé, els logs han de ser dinàmics, és a dir, la plana ha de refrescar-se segons apareguin noves línies de log (i això vol dir Ajax). La idea és tenir quelcom com el tail -n 100 f ... del Linux. Per la naturalesa de les peticions Http, no podem arribar a tenir la funcionalitat del tail, però podem atracar-nos-hi un poc. Aquest article explica com ho podem fer utilitzant Django, Python i jQuery.
El javascript
La part del navegador ha de refrescar-se automàticament i sols el tros que correspongui a la visualització dels logs. A cada refresc haurà de cridar al servidor, obtenir la informació del log i presentar-la.
Per aconseguir això utilitzarem Jquery i un afegitó anomenat Timers. Aquest plugin ens permet definir de manera una funció que s'executarà cada x milisegons fins que l'aturem o tanquem el navegador.
El temps de refresc dependrà de la nostra aplicació, i el truc està en donar-li un temps un poc menor que la velocitat a la que la nostra aplicació genera les línies de log. No fa falta mirar-s'hi gaire, sols és per donar una major sensació d'actualització en temps real i que es mostri la informació línia a línia. Si li donam un temps major farem menys peticions i la presentació del log potser es faci per blocs de línies.
També necessitarem fer una cridada Ajax al servidor per a que ens doni les línies de log. Això ho podem fer directament amb jQuery, amb la funció jQuery.ajax per exemple. Veurem que a més del text del log necessitam la darrera posició llegida, així que farem servir el getJSon, que ens permetrà obtenir la informació de manera més estructurada.
El servidor
Per simular el tail farem un poc de trampa. La primera vegada que es faci la petició ens situarem al final del fitxer de log i la segona ja enviarem la informació. És a dir, mostram al informació a partir de la segona vegada que es crida la funció. Com que el temps es suposa que és petit no té massa importància i simplifica molt la programació. Hem de tenir en compte que l'obtenció de log ha de ser ràpida.
Per a posicionar-nos farem servir la funció seek i tell ens donarà la posició resultant una vegada llegit el fitxer. Aquesta posició és la que anirem passant a cada petició, de manera que quan tornem a llegir el log, ho farem a partir de la darrera posició llegida. A l'exemple a més he fet servir la funció reverse per tal d'ordenar la llista de línies llegides de més nova a més antiga i simular l'scroll.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | from django.http import HttpResponse from django.utils import simplejson def _tail(f, actual = 0): """ Returns a tuple with the actual position on the file and the last read lines in html format. """ text ="" if actual == 0: f.seek(0, 2) else: f.seek(actual) log = f.readlines() if log: log.reverse() text = "<br/>".join(log) return f.tell(), text def tail(request): "Tail simulation" f = open('sample.log', 'rU') pos = int(request.GET['pos']) pos, msg = _tail(f, actual= pos ) f.close() data = {'msg': msg, 'pos' : pos } return HttpResponse(simplejson.dumps(data)) |
Fixem-nos que el que tornam és una estructura json, creada a partir d'un diccionar Python mitjançant el simplejson.
A més consumim la posició del fitxer des de la que hem de començar a llegir, que vindrà donada pel paràmetre get. No he posat validacions ni tractament d'excepcions, ho deix com a exercici per al lector (això sempre queda bé dir-ho quan un no té massa ganes de fer feina :-P )
Amb el que ara veim del codi de servidor, el codi javascript ja és entenidor:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | <script type="text/javascript"> $(function() { var pos = 0; var demos = $("div.wrapper div.demos"); var active = false; $('#log').ajaxStart(function(){$('#loading').show()}); $('#log').ajaxStop(function(){$('#loading').hide()}); $('.controlled-interval', demos). find('.start').css("cursor", "pointer").click(function() { if (!active) { active = !active; $('#log').everyTime(1000, 'controlled', function() { $.getJSON( "/log/tail/?pos="+pos, function(data) { if (data.msg !=''){ $("#log").prepend(data.msg+'<br/>'); } pos = data.pos; } ) }); } }).end().find('.stop').css("cursor", "pointer").click(function() { if (active) { active = !active; $(this).parents("div"). find('#log').stopTime('controlled'); } }); }); </script> |
Qui fa la feina és $('#log').everyTime(1000, 'controlled', function() qui es que manté el timer. Cada vegada que passa un segon (1000 ms) es crida al la funció del servidor amb la posició que acabam de llegir. El primer cop no tenim aquesta posició i la inicialitzam a zero, d'aquí que necessitem dues cridades a la funció per obtenir el primer log.
Notem com és de simple manipular el json a Javascritp. data té el text que hem d'escriure i la darrera posició de l'arxiu. Si el text està en blanc simplement ens limitam a actualitzar la posició; si hi ha contingut el posarem dins del div amb identificador log que tenim definit dins la plana.
S'hi pot fer molta més: posar-hi més disseny, podríem fer que es retornàs ja informació la primera vegada que es crida, tenir un reset per a que cuan continua el log sols venguin les darreres línies i no tot el bloc, però la idea és la mateixa:
- fer servir un timer
- fer servir ajax enviant la darrera posició on hem arribat
- fer servir seek i tell per posicionar-nos dins l'arxiu
Com és habitual l'exemple ho podeu davallar d'appfusedjango, o directament un svn co http://code.google.com/p/appfusedjango/source/browse/#svn/trunk/tail
Hi trobareu també una petita utilitat anomenada generate_log.py executant-la en una consola escriu línies de text que poden ser llegides per l'exemple.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python Django
Carregant imatges
Escrit per Aaloy a 19 de April , 2009 a les 11:35 p.m.
Normalment quan treballam amb imatges amb Django ho feim des del punt de vista de disseny, és a dir, posam les imatges al directori on s'han de servir i per avall. Potser a vegades hem fer servir quelcom com el Django Photologue per a tenir les fotografies més estructurades dins la nostra aplicació.
Què passa però, si el que volem és carregar les fotografies des d'un script a la nostra base de dades, o quan ens trobam que la informació no ve pels canals habituals d'una imatge que es puja mitjançant un formulari.
Aquest és el cas que tractarem en aquest apunt. Tenim una imatge que ens arriba codificada en base64 i el que volem és afegir-la amb un petit comentari a la nostra aplicació.
El model que farem servir és tan senzill com això:
1 2 3 4 5 | from django.db import models class Photo (models.Model): image = models.ImageField(upload_to='photos') comments = models.TextField() |
La imatge ens ha arribat com a una cadena de text. El contingut ho podeu trobar al subversion del projecte appfusedjango.
El primer que hem de fer es decodificar la imatge, després crearem una instància de la classe Photo, li assignarem el contingut, el comentari i guardarem. Fins aquí supòs que tothom d'acord.
El problema, però, és que ImageField suposa que li passarem una objecte del tipus File i nosaltres el que tenim és una cadena de text. Necessitarem per tant simular aquest tipus de dada de manera que puguem tractar amb informació que no vengui directament d'un fitxer de text. Ni més ni manco el ContentFile. Aquesta classe que podem trobar a django.core.files.base el que fa és precisament això.
Una altra de les coses que hem de fer és guardar la imatge i assignar-li el nom. Per fer això haurem de crear el nostre objecte Photo, guardar la imatge i després guardar-ho tot a la base de dades.
Anem a veure com quedaria:
>>>import base64 >>>from django.core.files.base import ContentFile >>>from sample.models import Photo >>># ja tenim tot el necessari >>>raw_data = base64.b64decode(open('test/encoded_logo.b64').read()) >>># acabam de llegir les dades, podrien arribar directament >>>foto = Photo() >>>foto.image.save('the-image-name.gif', ContentFile(raw_data)) >>>foto.comments = "Django & Python rules!" >>>foto.save()
El pas del 'image.save' és necessari perquè Django no guarda les imatges per defecte dins la base de dades sinó al sistema de fitxer (de fet podem guardar-ho allà on ens vengui de gust gràcies a les possibilitats del custom storage) així que necessitam definir tant el nom de la imatge com les dades. A la definició del camp ImageField ja li hem dit que voliem deixar les imatges a la carpeta photos que estarà dins el directori que tinguem definit com el nostre MEDIA_ROOT.
El projecte que he pujat serveix per demostrar la idea. Per provar-ho basta fer un
$ python manage.py shell
des del directori del projecte imatges per a convèncer-vos que la cosa funciona veient com es van creant les imatges dins la carpeta media/photos/ del projecte.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python Django
Nou ressaltat de sintaxis pel blog
Escrit per Aaloy a 11 de April , 2009 a les 5:24 p.m.
Fins ara Trespams tenia un ressaltat de sintaxi basat en Javascript, el que feia que no resultàs molt natural escriure apunts amb molt de codi font, ja que significava tenir que posar codi html dins el markdown per tal de marcar aquell tros de codi com a ressaltable pel Javascript.
Com a part de les modificacions he canviat això pel ressaltat basat en Pygments.
Aquest plugin permet fer servir tota la potència de Pygments per al ressaltat, podem resaltar HTML, plantilles Django, Javascript, Java, gairebé qualsevol cosa, i a més fent servir una sintaxi molt més natural, basta afegir un SheBang típic de Unix per a indicar el llenguatge.
La implementació està pensada per a no generar el codi HTML des de Markdown cada vegada, sinó que es guarden dues versions, una amb el codi original i l'altra amb el codi convertit a HTML i ja renderitzat amb els plugins. Això fa que el guardar l'apunt sigui un poc més lent (ha de convertir, reindexar i guardar) però la plana es pot mostrar molt més ràpidament. Optimització prematura? Potser sí, però tanmateix és d'aquelles coses que consideraria una millor pràctica.
El canvi fa que el codi antic no aparegui ressaltat, a poc a poc ho aniré canviant així com vagi revisant els apunts. El que no fa (crec) és trencar res, manté el codi dins un <pre> però no ho ressalta.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python Django
Django regroup
Escrit per Aaloy a 10 de April , 2009 a les 7:36 p.m.
He fet quatre cosetes al programari del blog, per tal de mirar de passar al màxim la validació del w3c, encara tenc problemes amb els pre que em genera el markdown dins paràgrefs i que no passen la validació, però al manco ara la plana es veu prou bé amb Konqueror.
Fent neteja m'he trobat amb la necessitat de refer la jerarquia de l'històric d'apunts. No era gens neta i com que ara el blog té un menú prou potent, he decidit posar molta cosa que estava al lateral com a opció del desplegable.
Per fer la jerarquia d'articles el que es ja el primer de tot és obtenir la llista d'arxius. Això ho feim cridant un tag creat ad-hoc pel blog
{% get_yearly_archive as archive_list %}
que el que fa és executar
Entry.objects.current_active().dates('pub_date', 'month', order='DESC')
i posar-ho a una variable que pot ser usada a la plantilla.
Amb aquest tag obtenim la llista de mesos en els que hi hem fet apunts. Un element d'aquest llista és per exemple:
datetime.datetime(2008, 2, 1, 0, 0)
Com podem veure és un tipus datetime de python i com a tal podem obtenir-ne fàcilment l'any objecte.year o el mes objecte.month.
El que volem, com dic, és fer una jerarquia, és a dir, tenir una cosa com:
- 2009
- Abril 2009
- Març 2009
- 2008
- Desembre 2008
Això normalment duria força feina, però és aquí quan hom veu que Django està pensat per als reptes de la vida real, ja ve amb un template tag predefinit que ens permet fer agrupacions, el regroup
Donada una llista ordenada regroup ens crea una estructura de dades que contindrà els elements pels quals volem fer el grup i dins aquests els element de la llista que tenen aquest element.
En el nostre cas hem posat l'historial dins una variable anomenada archive_list, que recordem és una llista de datetime. Farem
{% regroup archive_list by year as historial_list %}
Amb això hem creat la nostra estructura de dades. Fixem-nos que l'exemple que duu la documentació de Django diu que regroup té com a paràmetre una llista de diccionaris. És part de la gràcia del tipat feble, pel que fa al funcionament de la funció l'estructura datetime es comporta com espera l'iterador groupby que és el que fa servir internament.
Podem simular-ho perfectament a la consola de iPython
1 2 3 4 5 | >In [43]: p = itertools.groupby (x, lambda z: z.year) >In [44]: for i in p: > ....: print i[0] > ....: for j in i[1]: > ....: print j |
Ja tenim l'estructura de dades, així que ara sols quedar recorre i presentar la informació tal com la volem. Per això cal tenir en compte que la nostra estructura defineix la variable grouper que fa referència al valor del camp pel qual estam fent l'agrupació
1 2 3 4 5 6 7 8 9 10 11 12 | {% for year in historial_list %} <li><span class="dir">{{year.grouper }}</span> <ul> {% for d in year.list %} <li><a href='{% setting "BLOG_ROOT" %} {{ year.grouper }}/{{d|date:"m" }}/' class='menu_content'> {{ d|date:"M Y" }}</a> </li> {% endfor %} </ul> </li> {% endfor %} |
Com és habitual, és més llarg d'explicar que de fer.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python Django
Comentaris funcionant (esper)!
Escrit per Aaloy a 04 de April , 2009 a les 12:26 a.m.
Gràcies a Hugo me n'he assabentat que la darrera actualització del blog havia fet malbé el sistema de comentaris.
He pujat una nova versió sense el codi de depuració que feia que els comentaris no es poguessin processar ja que hi havia un punt de ruptura :(
Bé, res greu, coses de les actualitzacions a les males hores del vespre. En Pau també m'ha passat una incidència amb la visualizació del calendari amb Firefox 3.5. Pau, d'això se'n diu viure al límit!
Encara he de netejar molts divs innecessaris de l'anterior disseny. Vull jugar també amb algunes APIs de llocs socials i integrar-les, una de les primeres segurament serà la de Delicius.
Com que a mi també m'agrada viure perillosament estic aprofitant l'edició del blog per provar les versions de desenvolupament de Netbeans per Python. Estic tirant de les construccions del Hudson i provant-ho damunt el PowerPC.
No puc comparar-ho amb l'Eclipse perquè tanmateix damunt el PowerPC com ja he contat l'Eclipse no va gens bé, així que ja no hi ha comparació possible.
Res, que si algú s'anima a posar un comentari donaré per tancat el bug!
Traducciones/Translations by apertium
8 comentaris, 0 trackbacks (URL) , Tags: Python Django
Python més ràpid
Escrit per Aaloy a 28 de March , 2009 a les 11:42 a.m.
En Miquel ahir em va fer un enllàc vist pel Menéame. Reseguint la cadena d'enllaços arribam al projecte unladen-swallow.
El projecte és força interessant, i si segons diuen tenen per objectiu augmentar la velocitat d'execució de Python fins a cinc vegades vol dir que li haurem de tenir esment. Tot i que el projecte no arribi a bon port, de bon segur que les contribucions que pot fer a la base de codi de Python seran important. Recordem que Google té en plantilla a Guido Van Rossum el "pare" i dictador benèvol de per vida de Python.
La cosa està, però en no caure en el parany de dir que com que s'està treballant en la velocitat d'execució de Python aquest és un intèrpret lent. En quant a velocitats d'execució el que ha de primar sempre és el fet de si el compilador o intèrpret és prou ràpid per la feina. Si sols miram la velocitat segurament encara acabaríem fent les coses en Assembler, però la cosa està en que normalment el punt crític en quant a l'execució no està tant en el compilador o intèrpret, sinó en l'algorisme que feim servir.
Escriure un bon algorisme està directament relacionat amb la capacitat del programador, per suposat, però el llenguatge també hi intervé. Un llenguatge mal d'escriure, mal de depurar fa molt més difícil programar algorismes òptims, ja que el programador no sols s'ha de concentrar en el què vol fer, sinó que també ha de pensar en com ho ha de fer amb les eines que té.
Un dels grans avantatges de Python és que ens permet concentrar-nos en el que volem fer més que en el com. El llenguatge flueix de manera natural, la relació entre línies de codi i funcionalitat és molt baixa, de manera que aconseguim molt amb molt poques línies, però a més, aquestes tenen una expressivitat que fa fàcil saber que estam fent.
Per una altra banda Python també ens ofereix una gran quantitat d'eines per enllaçar amb programes i llibreries de C, o eines com Cython que fan que fer extensions en C per Python sigui molt semblant a programar en Python mateix. La programació numèrica és un altre dels camps on Python brilla, permet tenir tota l'expressivitat del llenguatge a l'hora de dir el que s'ha de fer i delegar la feina a les llibreries específiques de C.
Esper que el projecte tengui molt d'èxit i que aviat en puguem veure els fruits, però pensau que escriure codi lent es pot fer en qualsevol llenguatge de programació.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python
Trucs de l'administrador de Django
Escrit per Aaloy a 19 de March , 2009 a les 11:50 p.m.
Encara que a la documentació de l'administrador ho diu, sovint estam tan acostumats a fer feina amb camps que ens oblidam que al list_display de l'admin de Django hi podem fer servir qualsevol atribut o mètode susceptible de ser cridat (entre d'altres opcions).
Això obre tot un món de possibilitats a l'hora de presentar informació en forma tabular dins l'admin, podem crear enllaços cap a altres seccions, mostrar imatges, el que se'ns pugui ocorre i que tengui algun tipus de lligam amb el model.
Un exemple ben senzill, suposem que tenim un model que té una imatge associada, el que voldríem és que a la informació ens aparegui aquesta imatge, llavors faríem:
Al model afegim
1 2 3 4 5 6 7 | def get_foto(self): if self.foto: return '<img src="%s" width="64">' % self.foto.url else: return "" get_foto.allow_tags = True get_foto.short_description = 'Foto' |
i a l'admin.py afegirem a la configuració de l'administrador del nostre model
1 | list_display = ('get_foto', ...) |
Podem complicar-ho tant com vulguem, un exemple ho tenim al Django Snippet d'Admin list Thumbnail, que complica la funció per a crear les miniatures de les imatges que es presentaran i disminuir així el pes de la plana.
El que és important d'aquest exemple és veure l'ús que es fa de allow_tags, si el mètode té aquesta propietat Django no escaparà l'html que li passem, donant-nos joc a presentar tot tipus de codi html, baix la nostra responsabilitat, clar.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python Django
Fent net
Escrit per Aaloy a 19 de March , 2009 a les 6:52 p.m.
Una de les primeres coses que estic fent al Blog és la part de neteja. El codi és heretat de Blogmaker i hi ha molta cosa que amb les noves versions de Django es pot fer d'una altra manera o senzillament que es pot fer quan abans no es podia.
Ara la part d'administració de Django es pot personalitzar bastant, no és per tirar coets i normalment si s'han de fer coses complexes preferesc crear un backoffice ad-hoc, però pel que és redactar un apunt ja va prou bé.
Això m'ha permès eliminar força codi relacionat amb la part de presentació dels apunts i l'edició. Com que estic fent servir Markdown per a l'edició dels apunts he posat un editor anomenat Markitup, que permet tenir un entorn més amigable per a l'edició de Markdown i personalitzar les accions.
Per posar el codi dins l'administrador ha estat senzill. Amb la versió 1.0 Django va separar la part de vissualtizació i edició del model, amb la qual cosa podem definir com s'editarà el nostre model mitjançant un objecte que hereda de admin.ModelAdmin. Un dels aspectes més interessants és que podem afegir arxius Javascript i css, de manera que afegir el javascript necessari per fer servir l'editor de Markitup enlloc del simple text area ha estat cods de fer
class Media:
"Javascript configuration for Entry model in Admin"
js = [(settings.BLOG_MEDIA_PREFIX + 'js/jquery.js'),
(settings.BLOG_MEDIA_PREFIX + 'js/entry_change_form.js'),
(settings.BLOG_MEDIA_PREFIX + 'js/markitup/jquery.markitup.pack.js'),
(settings.BLOG_MEDIA_PREFIX + 'js/markitup/sets/markdown/set.js'),
(settings.BLOG_MEDIA_PREFIX + 'js/editor.js')
]
css = { 'screen': (
(settings.BLOG_MEDIA_PREFIX +
"js/markitup/skins/markitup/style.css"),
(settings.BLOG_MEDIA_PREFIX +
"js/markitup/sets/markdown/style.css") )
}
A fer dissabte s'ha dit!
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python Django
Nova versió del blog de Trespams
Escrit per Aaloy a 18 de March , 2009 a les 10:56 p.m.
Avui hem posat en producció (beta total) una nova versió del programari que fa que aquest blog pugui llegir-se. Això potser ho haureu notat els que feis servir l'Akregator, ja que els fils RSS us apareixeran duplicats (al manco a mi me passa), em sap greu.
Les novetats són sobretot en la part tècnica: nou cercador, més javascript en la part d'administració i l'execució baix un entorn virtualenv que permetrà fer-ne actualitzacions de manera separada de la resta d'aplicacions Django del servidor.
Aniré escrivint damunt les millores així com tengui temps. Aquest apunt és sols per avisar que Trespams està en beta i que si peta miserablement i m'ho voleu fer saber us estaré agraït.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python Django
Llibreries per a la manipulació de Dates
Escrit per Aaloy a 13 de March , 2009 a les 5:44 p.m.
Aquests dies m'ha tornat a pegar per a fer feina al Blog. En Bernat m'ha creat un virtualenv al servidor i ho aprofit per anar fent-hi quatre coses.
L'aspecte gràfic no canviarà per ara, si ho fa serà per convertir-se en més minimalista encara, el que sí canviarà és la part interna i les eines d'administració.
Fent feina amb l'administració m'he topat amb la necessitat de manipular dates amb Javascript. La llibreria Javascript que he posat per a gestionar taules Datatables(per l´unic motiu que tenia ganes de provar-la) no gestiona bé formats que no siguin el de Date de javascript, molt anglosaxó, ell.
Per arreglar-ho vaig tirar d'una llibreria de Javascript que ens permet manipular dates i formats de la manera que vulguem, i això m'ha fet recordar la conveniència de deixar per escrit un grapat de llibreries de manipulació de dates que extenen les que ja tenen els meus llenguatges de programació preferits:
Datejs Magnífica llibreria per a javascript. La versió "estable" es un poc antiga però fa el que ha de fer i també hi ha la del subversion, que encara no he provat, però que serà el que faré quan acabi aquest apunt. Un petit emperò, no sé que fa, però me deixa el Firebug torrat i ben torrat, necessita gairebé cinc minuts per tornar en sí.
python-dateutil s'està convertint en una referència obligada per a la manipulación de dates en Python, i això que Python de per sí ja ho fa fàcil.
python-egenix-mxdatetime un vell conegut per als qui hem tractat amb bases de dates amb Python. És la llibreria recomanada per la seva potència i rapidesa. L'anterior potser té la novetat i la senzillesa però la llibreria d'Egenix té la solvència que dóna l'edat.
Joda Time l'equivalent Java de les llibreries anteriors. Forma part de les llibreries que sempre posa a qualsevol projecte Java.
Abans de reinventar la roda (o el calendari) no oblideu fer una ullada a aquestes llibreries.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Informàtica Python Java
Validació de formularis amb Ajax, jQuery i Django
Escrit per Aaloy a 01 de March , 2009 a les 2:37 p.m.
Validació Ajax amb Django
A un dels projectes que estam fent el client va demanar una funcionalitat que requeria que s'enviàs un formulari al servidor i se'n fessin les validacions, però que la plana no es tornàs a recarregar. Un treball per Ajax, se'ns dubte. El problema era que tal com funciona el mecanisme habitual de processament de formularis amb Django, es requereix que es torni a recarregar la plana.
Una opció podria ser la de fer tota la validació del formulari amb Javascript, però llavors tendríem el perill de que l'usuari desactivàs el Javascript al navegador i pogués enviar dades directament sense validar. Podría fer-se tot per duplicat, és a dir, fer la validació amb Javascript i també al servidor, però això va en contra de la norma DRY (Don't repeat yourself).
Així doncs el que volem és el següent:
Enviar el formulari per ajax, però que sigui també possible fer un POST normal.
El servidor ha de fer les validacions i la plana presentar el missatge d'error si hi ha problemes.
Primer sense javascript
El primer que hem de fer és veure que tot funciona abans de posar-hi el javascript, així que crearem la nostra aplicació, crearem el formulari i hi posarem les valicacions que vulguem.
Farem un formulari molt senzill, el típic formulari de contatcte, però ho aprofitarem per introduïr-hi una opció nova a Django 1.0: la personalització dels missatges de validació.
from django import forms class ContactForm(forms.Form): "Defines the login for as in the Django sample" subject = forms.CharField(label="subject: *", max_length=100) message = forms.CharField(label="Request", widget=forms.Textarea(attrs={'rows':'10', 'cols':'80'})) email = forms.EmailField(label = "Your email *", max_length=120, error_messages = {'required': u"No e-mail, no message"}) cc_myself = forms.BooleanField(required=False) def clean_message(self): "We wan't to verify that it containts some words" msg = self.cleaned_data['message'].strip() if len(msg.split(None)) >5: raise forms.ValidationError(u"Really? This is quite short for a message") return msg
La manera més ràpida de mostrar el formulari és quelcom com
<table>
<form action='.' method="POST">
{{form}}
<tr><td span="2"><input type="submit" value="send" name="enviar" /></td></tr>
</form>
</table>
Però té un problema, que no controlam on es posen els missatges d'error i nosaltres volem controlar-ho. En aquest cas, i per simplicitat, posarem tots els missatges d'error a la part superior de la pantalla. Així que hem de rescriure la plantilla per a que ho contempli.
El nostre formulari queda doncs com
{% if form.errors %}
{{ form.errors }}
{% endif %}
<table>
<form action='.' method="POST" >
<tr><td>{{form.subject.label}}<td>{{form.subject}}</td></tr>
<tr><td>{{form.message.label}}<td>{{form.message}}</td></tr>
<tr><td>{{form.email.label}}<td>{{form.email}}</td></tr>
<tr><td>{{form.cc_myself.label}}<td>{{form.cc_myself}}</td></tr>
<tr><td span="2"><input type="submit" value="send" name="enviar" /></td></tr>
</form>
</table>
És a dir, ara tenim exactament el que teníem abans (no us hi fixeu amb la maquetació), però ara si hi ha errors es presentaran a la part superior del formulari.
Concentrem-nos ara en la manera de presentar els errors. Com que la nostra idea és que es puguin mostrar els errors que venguin per Ajax, el que farem és no presentar-los així, sinó que els posarem dins un div i farem que aquest es presenti o no en funció de si hi ha errors.
{% block errors %}
<div class="errores" {% if not form.errors %} style="display: none" {% endif %} >
<p id="error_msg">
{{form.errors}}
</p>
</div>
{% endblock errors %}
Això a efectes pràctics és el mateix que el cas anterior, ja que com que si no
hi ha errors from.errors no mostrarà res. El que sí hi ha ja és
tota l'estructura que ens servirà per mostrar els errors dins l'arbre DOM de la
plana web.
I ara i afegim l'Ajax
Necessitam tres coses: enviar el formulari per ajax, que si hi ha errors de validació els puguem presentar i que si tot va bé es faci la redirecció cap a la plana que toqui.
Hi ha alguns projectes que volen fer aquest tipus de coses de manera més o manco genèrica, però ara per ara no n'hi ha cap que em convenci, així que millor ho feim a mà. Si més no us deixo alguns enllaços:
El que sí faré es manllevar codi d'aquests projectes per als nostres propòsits, especialment del Django Ajax Validation.
En concret, adaptam el codi que ens permet obtenir els errors i passar-los a una estructura json:
class LazyEncoder(JSONEncoder): def default(self, obj): if isinstance(obj, Promise): return force_unicode(obj) return obj def validate(request, form, new_url=''): if form.is_valid(): data = { 'valid': True, 'url': new_url } else: if request.POST.getlist('fields'): fields = request.POST.getlist('fields') + ['__all__'] errors = dict([(key, val) for key, val in form.errors.iteritems() if key in fields]) else: errors = form.errors final_errors = {} for key, val in errors.iteritems(): if key == '__all__': final_errors['__all__'] = val if not isinstance(form.fields[key], forms.FileField): html_id = form.fields[key].widget.attrs.get('id') or form[key].auto_id html_id = form.fields[key].widget.id_for_label(html_id) final_errors[html_id] = val data = { 'valid': False, 'url': new_url, 'errors': final_errors, } json_serializer = LazyEncoder() return HttpResponse(json_serializer.encode(data), mimetype='application/json')
El validate és una funció prou genèrica, ens tornará una variable, valid que ens indicarà si hi ha errors de validació o no, la url on s'ha de redireccionar i la matriu d'errors.
Django ja posa al request una variable per indicar-nos si la petició s'ha fet per HttpRequest o no, request.is_ajax() això ens permetrà distingir com s'ha enviat el post i fer la validació d'una manera o altra
def index(request): redirect_url = '/thanks' if request.method == 'POST': contact_form = ContactForm(request.POST) if request.is_ajax(): return validate(contact_form, redirect_url) else: if contact_form.is_valid(): # do whatever you need as everything is valid return HttpResponseRedirect(redirect_url) else: contact_form = ContactForm() return render_to_response('index.html', {'form': contact_form})
El codi del view.py és d'allò més senzillet, sols feim que si la petició ve per post, tornam una cosa o altra en funció de si aquesta és una petició Ajax o si és una petició normal.
Fins ara no hem posat gens de javascript i tot segueix funcionant amb normalitat.
És temps de posar-ho les llibreries javascript. Ho farem amb jQuery, que és la que tenc més per mà, supòs que amb altres llibreries no hi ha d'haver cap problema, i a més faré server un plugin força bo per al tractament de formularis amb jQuery, el jQuery Form Plugin.
Com presentar els missatges, si s'han de presentar tots, els efectques que volguem, ja es cosa nostra. El json el que ens torna és l'identificador del camp i una matriu amb tots els errors que hi hagi. El procés que facem ja és cosa nostra.
$(document).ready(function(){
form_options = {
timeout: 3000,
dataType: 'json',
type: 'POST',
beforeSubmit: function(formData, jqForm, options) {
// you can add additional validation here and return
// false if it's not valid
jQuery('#boton').toggle();
},
success: function(responseJson, statusText) {
if (responseJson.valid) {
// redirect to hte new url
document.location.href = responseJson.url;
} else {
// create the error structure
var msg = ""
for (key in responseJson.errors) {
camp = key.split('_')[1];
msg = msg + camp+":"+responseJson.errors[key][0]+"<br/>";
}
$('#error_msg').html(msg+'<br/>');
$('.errores').show(100);
jQuery('#boton').toggle();
}
}
};
$('#testform').ajaxForm(form_options);
});
A l'exemple el que he fet és montar un missatge amb el primer error de cada camp sols a efectes demostratius, podeu fer el que us vengui millor: validar abans d'enviar, mostrar efectes als camps dels errors, mostrar un diàleg, sols estau limitats per la vostra imaginiació i el Javascript.
El codi complet de l'exemple l'he pujat al projecte appfusedjango
Traducciones/Translations by apertium
6 comentaris, 0 trackbacks (URL) , Tags: Python Django
Llibres a febrer de 2009
Escrit per Aaloy a 26 de February , 2009 a les 9:19 p.m.
Ahir em vàren arribar dos llibres nous:
- jQuery in Action de Bear Bibeault i Yehuda Katz, editorial Manning, ISBN 978-1933988351
- Django 1.0 Template Development de Scott Newman, editorial Packt Publishing, ISBN 978-1-847195-70-8
Pels títols ja sabeu de què van, així que com sempre us dic un poc el que esper de cada un i les primeres impresions:
JQuery in Action
De l'estil d'aquesta sèrie de Manning: bona edició i continguts interessants explicats correctament. Estic encara als primers capítols de la primera lectura ràpida i m'està agradant força. Al JQuery l'estic fent servir cada cop més i necessitava un llibre com aquest per poder-ne tenir una idea completa. Hi ha molta documentació del JQuery, però està prou dispersa com per a que un llibre com aquest tengui sentit.
Django 1.0 Template Development
Aquest ho vaig comprar perquè m'interessava veure com s'introduïa el tema del desenvolupament Django orientat a dissenyadors més que a programadors. Com sabeu sóc de la opinió que el dissenyador/maquetador ha de formar part activa dins un equip de programació web, amb el mateix nivell d'implicació que un analista/programador. Això vol dir fer anar un subversion, maquetar amb un editor de text com Eclipse o Netbeans i com no entendre com es poden fer servir les plantilles Django de la mateixa manera que es coneixen les possibilitats del CSS. La conclusió que en tenc per ara és: a poc a poc i amb molts exemples. Me pareix una bona aproximació i esper tenir l'oportunitat de posar-ho en pràctica. El llibre pot ser un bon material de referència per a propers cursos.
Traducciones/Translations by apertium
2 comentaris, 0 trackbacks (URL) , Tags: Llibres i revistes Python Django
Django a l'empresa: liquidacions de despeses
Escrit per Aaloy a 22 de February , 2009 a les 6:57 p.m.
Aquesta setmana hem posat a preproducció una aplicació interna per a la gestió de les despeses feta amb Python, Django i Postgres. La idea és poder saber quines són les despeses més comuns per tal de fer-ne un seguiment i si s'escau poder fer una negociació amb els preoveïdors habituals.
Per això era necessari que les liquidacions de despeses que fins ara es feien amb un excel (quin mal fan els excels a les empreses!) es facin ara mitjançant una aplicació web. D'aquesta manera a la primera etapa l'usuari té exactament el que tenia abans, a saber, una fulla de paper que el seu cap pot signar i després presentar al caixer; però a més l'empresa començarà a tenir dades que es podran analitzar.
L'autentificació dels usuaris es fa contra l'Active Directory de l'empresa, en les darreres versions de Django és trivial canviar de sistema d'autentificació i han aparegut diferents snippets que ens permeten canviar el sistema d'autentificació estàndard per un altre. En el meu cas l'snipet d'autentificació per l'Active Directory ens ha anat força bé. De la mateixa manera seria trivial fer l'autentificació contra un LDAP o contra un altre sistema és força senzilla i la documentació de Django és molt aclaridora.
En aquesta aplicació a més de l'autenticació hem fet molta feina amb jQuery, hi ha moltes dades amb autocompletat (per les companyies aèries i pels aeroports per exemple), validacions, quadres de diàleg modals, etc. Es tractava de fer una aplicació el més àgil possible, però sense deixar de ser una plana web, per tal de no assustar massa als nostres usuaris. És una cosa en la que s'ha d'anar alerta, m'agrada molt l'article de Jefff Atwood Avoiding The Uncanny Valley of User Interface que explica el perquè es pot produïr un rebuig de l'usuari quan les coses volen ser massa paregudes al que ja coneix però sense arribar a ser-ho. En el nostre cas els usuaris conèixen les aplicacions d'escriptori i les interfícies de Forms i qui més qui manco sap fer anar un navegador web.
Podríem haver fet una aplicació RIA amb Extjs per exemple, però per molts dels usuaris que faran servir l'aplicació veurien que és una aplicació d'escriptori sense notar que s'executa al navegador. Per ells això implica complexitat, que algú en faci la formació individualitzada com es fa a les altres aplicacions. Massa cosa per el que ha d'esser una aplicació que té per objectiu imprimir un paper. Així doncs vàrem preferir que l'aplicació es semblàs a una plana web, amb formularis i enllaços, on el que s'imprimeix també és una plana web. Potser encara així algú trobarà l'aplicació complexe, però crec que ja serà per por i reticència al canvi més que per mor de l'aplicació en sí.
L'aplicació ha estat desenvolupada per un equip relativament nou en la programació Python i Django i tot i això s'ha pogut entregar en el temps previst (que ja considerava aquest fet per una altra banda). Això no fa més que refermar-me en el convencimient de que a més de la potència del llenguatge hem de considerar també la corba d'aprenentatge a l'hora de triar amb què farem el desenvolupament.
En aquest projecte i en els temps de crisi en que estam, encara em resulta sorprenent que hi hagi algú que es qüestioni si la base de dades en lloc de ser Postgres no hauria de ser Oracle. En aquests casos m'agradaria poder amollar allò de "It's about costs stupid!" i dedar-me tan ample. El que més em sobta és que s'amolla com si tu fossis el que has de justificar la decisió, quan realment hauria de ser a l'inrevessa. Per què fer una cosa damunt Oracle quan es pot fer amb Postgres (o Mysql)? Amb preocupa aquest tipus d'inèrcia informàtica, de curtor, que no s'atura a pensar en els costs actuals i futurs, tant és si hi ha al mateix moment algú d'Oracle demanant pel nombre de llicències. Sorprenent!
Però bé, és d'aquestes coses que acabes assumint com a comportament normal i que potser ni amb tota la pedagogia del món s'arribarà a res. Tenc l'esperança que aquesta crisi que vivim al manco servesqui per a que la gent es plantegi un poc la relació costs beneficis. Sols que s'aturi a pensar-ho un moment de ben segur que ja no caldrà el justificar el perquè s'ha anat cap a una solució de programari lliure. La part ètica? Què voleu que us digui, si la part econòmica ja costa (i estam parlant d'empreses!) imaginau-vos que pot arribar a costar que s'entengui el que representa el programari lliure en la vessant social i ètica.
I és una llàstima, perquè hi ha moltes empreses sortint de l'armari, que publiquen el codi que fan servir internament en forma de projectes lliures, de llibreries. El darrer exemple que se m'acud ve del Washington Times que ha obert un blog amb un bon conjunt de projectes Django o també un post damunt robots controlats amb Python.
Projectes com els que treim darrerament venen a mostrar que la tan cercada reutilització, els mètodes per lluitar contra la crisi del software, potser són molt més aprop del que ens pensam. El codi lliure permet la reutilització a nivells mai somiats, Python a més ho fa més fàcil, Django ho fa divertit per la web.
Traducciones/Translations by apertium
6 comentaris, 0 trackbacks (URL) , Tags: Python Django
Caçant bubotes
Escrit per Aaloy a 14 de February , 2009 a les 1:43 p.m.
Poc a poc hem anat evolucionant la nostra arquitectura d'aplicacions des de aplicacions monolítiques fetes amb J2EE cap a aplicacions on la capa de serveis està en Java (per ara!) i aquests es consumeixen amb Python, utilitzant Django com a bastiment web.
Per a consumir serveis SOAP feim servir una llibreria anomenada ZSI que ens permet generar les classes Python a partir el WSDL dels serveis.
ZSI és un projecte que avança molt a poc a poc, veus que no està mort, que funcina, però la versió 2.1 fa estona que està en alfa. Tot i això, la versió 2.0 funciona prou bé com per poder consumir els serveis sense problemes.
L'altra dia però, ens vàrem trobar amb un problema d'aquests que classific com a "bubota". Atacàvem al servei que tenim de Transfers i tot anava com a la seda, atacàvem al d'excursions i el mateix. Atacàvem als dos dins la mateixa aplicació i l'espai de noms es feia un embolic, de manera que ens posava l'espai de noms del primer servei que s'executava.
Ho va descobrir en Juanjo i jo li deia que no podia ser fins que vaig fer un petit test de manera independent de l'aplicació que estam fent i ho vaig tocar amb les mans. Hi havia un problema i ara el problema era poder identificar a on, al webservice (poc probable), a la capa de servei que cosumia el SOAP (probable), al mapeig del ZSI (menys probable) o al ZSI en si (encara menys probable).
Quan un es troba amb un problema així, el primer és anar de més probabilitat a menys i anar descartant coses. La idea a més és aprofitar que hom està fent la depuració per a refactoritzar el codi, de manera que la feina de depuració serveixi a més per deixar un codi més clar i per tant més fàcil de depurar (recordau la primera regla de la refactorització: l'aplicació ha de funcionar exactament com funcionava abans, no introduïm nova funcionalitat).
Així doncs va començar un procés de refactorització de la primera capa, la que consumia el servei mapejat amb ZSI. Vaig organitzar millor el codi en paquets, vaig eliminar importacions innecesàries i vaig aillar totalment la part de transfers de la part d'excursions. Els tests però treien sempre el mateix, error quan atacàvem als dos serveis a l'hora.
La següent passa va ser anar a veure el codi generat pel ZSI (amb wsdl2py). Els generador de codi van molt bé, però sovint són massa genèrics. Així que també vaig fer-ne la refactorització. Eliminar totes les importacións amb arterisc, canviar nom comuns als dos paquets de transfers i excursions, i passar la part de defnició de tipus Soap a un arxiu independent, de manera que sols importàssim els realment necessaris. Tampoc! Els tests seguian donant el mateix... Bé al manco la refactorització era conseqüent...
Ara ja sols quedava la passa de la depuració línia a línea, fins i tot anant al codi del ZSI. Per això vaig començar amb un depurador senzillet comp el pdb (amb la seva versió d'ipdb) i vaig poder identificar a quin punt hi havia el problema. Pareixia estar en les cridades que feia el codi generat cap el ZSI. Per a facilitar la depuració en aquest punt ja vaig passar a un depurador gràfic, el winpdb, ja que permet veure d'una ullada totes les variables locals i globals.
Entrant al ZSI vaig descobrir la bubota. El ZSI cacheja els tipus d'objectes generats, però de tal manera que ho fa de manera global a l'aplicació, per tant, si dos objectes tenenen el mateix nom (com era el nostre cas), retorna el primer nom generat amb el seus espai de noms (cagada del ZSI al meu entendre). Potser és poc comú el que feim, però crec que és un cas típic d'optimització prematura. Es cachegen els tipus generats potser sense importar-hi.
La solució doncs va ser llevar les cachés, fes que generàs el tipus cada cop. Esperava pot ser una pèrdua de rendiment, però no és així, pareix que fins i tot posar i treure de la caché és comparable al temps d'execució a la genereació del tipus. He d'afinar un poc més amb aquesta apreciació, però el que està clar és que per al consum que es fa del servei, la diferència de temps no és significativa a l'ordre dels milisegons, i del tot menyspreable si ho comparam amb el *lag * produït per les línees de comunicació. Amb la caché activada 1 segon, i sense 1 segon igual.
La bubota està caçada, els fantasmes desapareixen quan es fa la llum i amb tot el procés he après molt millor com funciona el ZSI per dintre.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python Django
Entorns de treball virtuals per Python
Escrit per Aaloy a 12 de February , 2009 a les 6:23 p.m.
Si he fet feina amb Python amb projectes diferents us haureu trobat amb algun d'aquest problemes:
La llibreria que heu devallat del svn per a un projecte té canvis, les necessitau pel projecte actual però són incompatibles amb el projecte anterior.
Necessitau provar l'aplicació que teniu amb les mateixes llibreries i versió que hi ha a producció. Podeu tirar de svn per la versió de producció, però les dependències de les llibreries han canviat.
Teniu tants paquets i llibreries instal·lats al
site-packagesque les utilitats d'autocompletat es tornen bojes per mostrar-vos les ajudes.
Per a resoldre tots aquets problemes hi d'altres semblants podem fer ús de dues utilitats com són el virtualenv i el virtualenvwrapper, creades per Ian Bicking i Doug Hellmann respectivament. Veurem en aquest article com fer-les servir.
El primer que hem de fer és instal·lar-les. Ho podem fer amb easy_install virtualenv i easy_install virtualenvwrapper. La primera utilitat és la que realment farà la feina, l'altra és un script que ens facilita el maneig i la gestió dels distints entorns.
Suposaré que ens trobam en la situació de que volem crear un entorn net, on crearem la nostra aplicació i que tendrà totes les llibreries i dependències necessàries per a executar-la. Per començar el primer que farem serà configurar el nostre entorn de treball
$mkdir ~/.virtualenvs
Ara editarem el nostre arxibu .basrch i hi afegim
export WORKON_HOME=$HOME/.virtualenvs source /usr/bin/virtualenvwrapper_bashrc
La localització del virtualenvwrapper_bashrc pot canviar segons la distribució, adaptau-la segons convengui.
Després d'editar el .bashrc feim un source ~/.bashrc per a activar els canvis i ja podem crear el nostre primer entorn virtual.
Crearem un entorn anomenat estable que tindrà la versió estable de Django i poca cosa més. Prèviament ens haurem baixat dita versió i l'haurem descomprimida a un directori temporal.
$ mkvirtualenv --no-site-packages estable $ workon estable
Això ens haurà creat un entorn de Python amb les llibreries per defecte. És el que li hem dit amb --no-site-packages. Si no li haguéssim posat aquesta opció, ho hagués creat, però amb tot el que tenim al site-packages actual, si ens interessa bé, però si no, com és el cas, millor pensar en crear els entorns virtuals fent servir aquesta opció.
Ara podem anar al directori on hem descomprimit Django i fer un python setup.py install. Si us hi fixau veureu que Django ara no s'instal·la al directory site-packages del sistema, sinó al del entorn virtuals. Això és així perquè hem activat l'entorn amb la comanda workon. Aquesta comanda ens permet veure els entorns que tenim definits i a més, posant-hi el nom del entorn, canviar d'entorn virtual, a partir del canvi, les comandes d'instal·lació via setup.py o easy_install es faran a l'entorn virtual actiu.
Si voleu tornar a l'entorn de treball del sistema podeu desactivar l'entorn virtual amb un deactivate.
Tenim un petit problema però, necessitam el PIL i és una tudada d'espai tenir-ho que instal·lar des de zero. Per això podem fer dues coses, o bé crear un enllàç simbòlic dins l'entorn virtual, en el nostre cas dins $WORKON_HOME/stable/lib/python2.5/site-packages/ o bé fer ús de la comanda que ens proporciona el virtualenvwrapper anomenada add2virtualenv. Així si executam
$workon estable $add2virtualenv /usr/lib/python2.5/site-packages/PIL
Hauríem afegit al nostre entorn virtual el paquet PIL del sistema. Ho podeu anar fent amb paquets que necessiteu, però teniu en compte que l'objectiu de l'entorn virtual és tenir un sistema net i no acabar amb tots els paquets que hi ha al sistema llincats.
Podem crear tants entorns virtuals com necessitem i vulguem, fins i tot un per cada aplicació. La comanda workon ens permetrà visualitzar-los i canviar entre ells amb tota facilitat.
Si optau per crear un entorn virtual per aplicació segurament trobareu molt útil saber que a directori bin del nostre entorn virtual podem crear dos scripts que d'existir s'executaran associats a l'entorn virtual, es tracta de postactivate que s'executa després d'activar l'entorn i predeactivate que s'executa abans de la desactivació.
En algunes aplicacions el meu postactivate és tan senzill com un canvi de directori cap a la carpeta de feina de l'aplicació i una actualització (via svn up) del codi.
Anem ara al tema de l'autocompletat. Com ja he comentat darrerament estic fent servir Netbeans per Python com a entorn de desenvolupament. Netbeans ens permet definir quins entorns d'execució farem servir (i gràcies a Xus vaig saber del cromo que deia que podíem fer-ho servir per a indicar a Netbeans que fes servir aquest entorn.
Una vegada creat el nou intèrpret de Python dins el Netbeans segurament encara haureu de pensar en fer una cosa més, assignar-ho al nostre projecte ja que en cas contrari tindria l'entorn antic. Així doncs anau a les propietats del projecte i assignau com a Python Platform l'entorn virtual que acabau d'afegir.
Podeu crear tants entorns d'execució de Python com siguin necessaris, cada un amb el seu entorn virtual associat i fer que sigui l'entorn d'execució per defecte del projecte. Això farà que l'autocompletat sols us mostri les opcions que es poden agafar d'aquestes llibreries, resolent un dels emperons més grans que particularment li trobava a l'autocompletat de Netbeans. Amb això i amb la recent descoberta de que depurar Javascript des de Netbeans és possible i més àgil que amb firebug (encara que ho faci servir, deu ser cosa del refresc del navegador), encara fa que em decante més per Netbeans com a entorn de desenvolupament per defecte per Python amb el permís de Vim, clar.
Us aconsello jugar amb els virtualenvs, fer proves, mirar quins paquets i utilitats feis servir més, si els vostres aplicatius s'executen bé en un entorn net (com possiblement serà l'entorn de producció), podeu crear-ne tants com vulgeu. Un entorn típic per a desenvolupar amb Django té un tamany de 35M (du -h $WORKON_HOME/estable/), que no és res pels tamanys dels discs durs actuals.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python Django
Balanç del 2008
Escrit per Aaloy a 31 de December , 2008 a les 11:32 a.m.
Aquest serà el darrer apunt d'aquest any, i com a tal toca fer balanç del que ha significat aquest 2008 que aviat s'acaba.
Programació
A l'aspecte de programació ha estat un bon any: Django ha tret la versió 1 i Python l'esperada versió 3. Hem vist com han aparegut força projectes basats en Django que marcan la línia cap a l'esperada reutilització de codi.
Ha estat l'any on personalment he fet molta més programació amb Django que en Java. Els tipus de projectes que han sortit feien que fos molt més ràpid i optim fer-ho d'aquesta manera. Alguns dels llocs web han tingut força visites i hem pogut comprovar el bé que se comporta Django.
L'aparició de Netbeans per Python també crec que és una notícia prou important. Fins ara pareixia que Python estava apartat dels plans de Sun (no així dels de Google com s'ha vist amb l'AppEngine) i pel que apunta pareix que a mitjà plaç i amb permís d'Eclipse i Aptana podria ser l'editor de referència per Python.
Gestió de projectes
He seguit amb discussions filosòfiques damunt el que és un projecte i el que no és. Per mi un projecte per definició ha de tenir una data d'acabament, però ja he perdut l'esperança de que algunes coses canviïn.
Scrum com a metodologia cada cop m'agrada més. Estic molt còmode amb la idea de que les persones són el més important de l'equip i de que el cap de projecte ha de ser un facilitador. Scrum s'adapta molt bé a aquesta manera de pensar i de fer.
De la família
Llums i ombres enguany. Llum pel naixement del meu segon nebot, ombres per la pèrdua de gent propera, en un cas molt jove que va omplir la família de consternació, i un petit ensurt amb el Pare que afortunadament no ha anat a majors.
Els meus menuts creixent dia a dia, enguany ja saben colcar en bicicleta (amb 3 sessions en tingueren prou per aprendre'n!) i trobar la IP del seu ordinador Linux.
Dels amics
Donar-vos les gràcies per ser-hi, per aguantar-me els acudits dolents i pels bons moments que hem passat junts. La vida no seria digne de ser dita vida sense els amics.
De la feina
La feia principal rara, moltes baixes, buids de poder i una fusió que pareix que no s'arriba a concretar. Personalment he demanat una reducció de jornada que esper es concreti al 2009. No m'agraden les situacions d'impàs i mentre tot es defineix prefereixo dedicar més temps a la família.
De la feina "pla B" bé, molt bé. Projectes molt interessants que esper es concretin molt aviat. El 2008 ha estat un any de transició, d'agafar embranzida per l'any següent i crec que s'ha aconseguit.
Gràcies a tots i totes per seguir aquest blog i pels comentaris que anau deixant. Esper que el 2008 hagi estàs profitós per les vostres vides. Ens llegim al 2009!
Traducciones/Translations by apertium
7 comentaris, 0 trackbacks (URL) , Tags: General Python Django
Django no és PHP ni JSP
Escrit per Aaloy a 27 de December , 2008 a les 1:38 p.m.
Alguna de la gent que s'atraca a Django per desenvolupar web ve de PHP o del món Java (amb JSP) i intenta aplicar les mateixes tècniques que havia fet servir abans, trocejant les planes i fent servir includes, desaprofitant la potència de les plantilles de Django.
Includes per la maquetació
Els includes existeixen en Django, però no tenen la mateixa importància que en PHP a l'hora de fer la maquetació.
Les plantilles a Django es poden heretar. Això és un concepte nou per la gent que ve de PHP o JSP, però és la manera de muntar les planes web. El que feim és definir la nostra plantilla base (o plantilles) i programarem per diferències. És a dir, quan hem creat la plantilla, la plana següent la maquetarem pensant "és com la plantilla base però amb aquesta secció i aquest altra diferent".
Cada una de les diferències la podem posar dins un bloc. Així les plantilles hereten els continguts i el blocs de les plantilles pare i podem sobreescriure els continguts dels blocs.
Això vol dir que normalment no trocejarem la nostra plana en capçalera, menú, contingut i peu, en quatre arxius diferents, sinó que estarà tot dins el mateix arxiu i el que farem serà definir distints blocs segons convengui o no sobrescriure'ls en les plantilles filles.
No hem de passar pena de posar massa blocs, de fet millor trocejar massa que massa poc. I encara així, sempre som a temps d'editar la plantilla base per anar afegint els blocs que necessitem.
Includes per a carregar llibreries
JSP té el concepte de taglibs per a realitzar funcions com el formateig (fmt), estructures de control (core), etc.
A Django la majoria d'aquestes estructures estan ja dins el llenguatge de plantilles, definint els tags i els filtres. Els primers realitzen accions complexes i contenen les estructures de control de fluxe, els segons ens permeten modificar el contingut final que es mostrarà a l'usuari.
Com al Java amb el JSP Django ens permet definir llibreries de tags i filtres que es poden utilitzar en la generació de la plantilla amb un simple {% load "nom-de-la-llibreria" %}.
Les plantilles de Django no permeten incloure codi Python i el que es pot fer és limitat. La idea és que la plantilla tracti sols amb la capa de presentació i tot el que requereixi tractar amb regles de negoci o funcionalitat complexa es delegui a la capa Python.
Els includes de Django
Estan pensats per evitar tenir que repetir codi no per a la maquetació dels continguts. Pensem en el cas que tenim funcionalitat semblant però que ha d'anar a plantilles amb unes estructures molt diferents. Llavors el que feim és extreure aquell troç de funcionalitat i posar-ho a un arxiu separat per tal que es pugui reaprofitar el codi.
És més, si la repetició encapsula funcionalitat i aquesta es pot reaprofitar en altres aplicacions l'adequat seria crear un tag que generàs l'HTML. Django proporciona fins i tot decoradors que ens permeten crear molt fàcilment plantilles html que agafin paràmetres, o crear tags que generin HTML tal i com nosaltres el volem.
En definitiva, abans de posar-vos a maquetar convé fer una ullada a la documentació de Django, començant per Django template for designers que ens introduirà en els principals conceptes, després pegar una bona llegida als tags i filtres i una vegada dominem Python anar cap a la creació de les nostres pròpies llibreries de tags.
Traducciones/Translations by apertium
4 comentaris, 0 trackbacks (URL) , Tags: Python Django
Cursos de Python i Django
Escrit per Aaloy a 23 de December , 2008 a les 6:03 p.m.
Els que em coneixeu segurament haureu notat que m'agrada ensenyar de la mateixa manera que m'agrada aprendre. Ensenyar permet compartir experiències i coneixements amb un nivell de comunicació que és difícil d'assolir en un llibre o un article, i poder ensenyar allò que a més t'agrada ho fa tot molt més divertit.
Com en moltes coses, per mi la màxima és fer les coses com m'agradaria que algú les fes si fossin per mi. Això sovint fa que m'ho prengui de vegades massa seriosament, sóc exigent amb els altres i per tant també ho sóc amb mi.
Per a que un curs sigui productiu la gent que hi assisteix hi ha d'anar mínimanent motivada. Una manera de tenir aquesta motivació és que la matèria que s'hi imparteix es vaig a utilitzar en un futur proper o ja s'estigui utilitzant.
Python i Django fa que sigui molt ràpid poder tenir un entorn de proves i començar a fer coses. La corba d'entrada és molt suau i es poden començar a fer aplicacions molt ràpidament, per tant, augmenten les possibilitats de que la gent ho pugui fer servir en el seu dia a dia, fins i tot si no s'hi dedica al 100%. Tasques d'administració de sistemes, scripts d'importació, generació de codi, etc. són molt ràpides de fer en Python i per tant es pot veure un resultat immediat del que s'ha après. La realimentació que s'aconsegueix, la gratificació de l'ego, fa que la gent pugui veure una utilitat en allò que fa.
A mi els formadors que m'agraden són aquells que a més de dominar la matèria (no ho doneu per suposat, no és la primera vegada que vaig a un curs on que l'impartia sols sabia el que deien les presentacions que duia preparades) hi fan feina. Sobretot en la part tècnica això es nota molt. Qui fa feina dia a dia amb una tecnologia a més de tenir-ne els coneixements també us podrà donar consells, millors pràctiques, trucs de la professió que no estan als manuals. Llavors és cosa de cada un aplicar-los o no, però el que està clar que a més d'una simple explicació de coneixements hi ha la part de transmissió d'experiència.
Per això m'agrada que els formadors no es dediquin professionalment a la formació, sinó que la seva feina principal impliqui fer feina amb aquella tecnologia i obviament m'aplic el mateix criteri. M'agrada ensenyar, però em trob molt més còmode amb mi mateix ensenyant allò que faig servir, en el meu cas Python, Django o gestió de projectes informàtics.
Ensenyar implica també preparar-se les classes. Per mi aquesta preparació no significa llegir-se la matèria (que també) sinó a més preparar exemples, la línia argumental de la classes i un conjunt de "plans bé". És a dir, tu prepares el que se suposa que serà el contingut de la classe d'aquell dia, però pot ser que s'avanci més ràpid del que s'havia pensat, o que sorgeixi més interès per un tema concret o que trobis que és millor fer un exemple més senzill per acabar de lligar el que s'havia explicat. Poder anticipar-se a tot això i tenir-ho previst també fa que s'avanci molt més en la formació. A mi que el formador se quedin pensant en el que ha de donar a continuació no m'agrada gens.
És difícil trobar gent bona per donar formació, de la mateixa manera que és difícil trobar bons programadors. Particularment aspir a que la gent acabi amb el convenciment de que després dels cursos en sap més que abans de començar, que la formació se li faci curta i es quedi amb ganes de saber-ne més.
Traducciones/Translations by apertium
6 comentaris, 0 trackbacks (URL) , Tags: Informàtica Python Django
Dos apunts d'avui
Escrit per Aaloy a 16 de December , 2008 a les 8:48 p.m.
Avui he llegit pels RSS dos apunts que m'han agradat:How Are You Staffing Your Startup? i Outsourcing Killed By Django And Ruby On Rails
El primer apunt reflexiona sobre el paper dels administradors de sistemes als equips de desenvolupament, a les startups. La veritat és que no hi puc estar més d'acord, especialment quan la feina té a veure amb la web.
Entenc la web com una feina d'equip, on es necessita, a més de la idea, els desenvolupadors que la programin, els creatius i maquetadors i la la gent de sistemes per a que ho posi en producció i tengui cura de l'estabilitat del sistema.
Pens que a part de l'èxit d'una aplicació hi té molt a veure l'entorn on es desenvolupa, tenir un entorn de preproducció adequat, tenir un entorn de producció escalable. Que la gent de sistemes pugui dedicar temps a monitoritzar l'aplicació, a millorar les eines que té a cercar o crear-ne de noves.
L'altra apunt fa referència a com Django i Rails poden canviar la mentalitat d'outsourcing de les empreses. Ambdós bastiments fan que el cost de les aplicacions sigui menor i que la quantitat de codi repetitiu que s'escrigui sia molt menor que en les aplicacions escrites en Java (o .Net donat el cas).
Potser l'article no està redactat de manera molt afortunada (ja veureu els comentaris), però crec que la idea és vàlida. Django i Rails permeten fer més coses amb menys gent, però a més fa que la gent millor encara destaqui més i sigui més productiva, ja que l'hem alliberada de gran part de les tasques repetitives que no aporten valor i que precisament són les que tenen més sentit externalitzar.
Això no vol dir que la gent de la India els països de l'Est o Sudamèrica no sigui creativa, sinó que senzillament no fa falta treure les coses fora quan a casa t'ho poden fer igual o millor a pràcticament el mateix cost i temps.
Dugem les coses un poc més enfora. Suposem un projecte gran, 100.000 línies de codi Java pel cap baix. Aquests tipus de projectes són els que normalment se durien cap a consultores de fora. Amb Django se pot convertir en un projecte de 20.000 línies tranquilament i llavors els projectes que es treien fora perquè no hi havia mans per al desenvolupament es poden posar en mans d'empreses d'entre 5-10 desenvolupadors amb garanties de que el projecte s'acabi i s'entregui. En poques paraules, es pot passar de les macro-consultores a les PYMEs altament especialitzades i localitzades fins i tot al territori de qui demana l'aplicació. En la meva opinió això és bo, ja que per una part abaratint els costs fa possible que es puguin fer altres projectes, però a més perquè s'està afavorint un treball de qualitat, no basat en la força bruta sinó en la capacitat de l'equip.
Traducciones/Translations by apertium
1 comentari, 0 trackbacks (URL) , Tags: Python Gestió de projectes
És temps de Python
Escrit per Aaloy a 08 de December , 2008 a les 1:55 a.m.
En Paul Graham a un conegut assaig deia que si un volia bons programadors tenia que anar cercant a gent que fes feina amb Python. Era per allà el 2004 i supòs que la gent de Google li va fer cas, un poc exagerats per això, posant en plantilla a Guido Van Rossum. A l'assaig es fa referència a que algú amb prou interès per aprendre un llenguatge minoritari com el Python hauria de tenir passió per la programació i per tant téndria mols números per ser un bon programador.
Potser ara Graham es decantaria per coses com Scala o Erlang, però tanmateix el que importa realment és que la gent que s'ha apropat a Python fins ara ho fa cercant alguna cosa millor, un llenguatge més manejable i que li permeti expressar en codi les seves idees.
Bastiments com Django, Pylons o Turbogears han donat una nova magnitud al llenguatge, posicionant-lo com un competidor de primera línia en el desenvolupament web.
La pròpia experiència indica que Python i un framework web com Django permet una productivitat un ordre de magnitud superior a la que s'obté en Java i una corba d'aprenentatge molt menor i més suau.
Aquests darrers mesos hem posat en producció dues web noves i estam a punt de llançar una web per a la gestió de congressos i events que ataca a un web service consumit en Python, tot això a partir d'un equip mínim de programació i en el darrer cas fins i tot a partir de gent que mai havia programat en Python. La programació és molt ràpida i l'escalabilitat i els temps de resposta de les webs tan bo o millor que les webs que tenim en Java. Dels continguts, què dir-vos? Programació no hi té res a veure ;)
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python
Python 3.0 ja és aquí
Escrit per Aaloy a 04 de December , 2008 a les 9:11 p.m.
Després d'anys de feina tenim la nova versió de Python aquí. La llista de novetats és força nombrosa i implica a més que es romp la compatibilitat cap enrera.
Tranquils no passa res! Python 3.0 representa el primer intent de rentada de cara a Python per a convertir-lo en el que serà un llenguatge fins i tot més potent que l'anterior, sense perdre la riquesa i expressivitat actual de Python, però solucionant d'una vegada problemes com el del tractament uniforme del tipus de dades sencer, l'unicode i tenir difernts maneres de fer el mateix per obtenir resultats semblants (range i xrange per exemple).
Als sistemes operatius seriosos poden conviure vàries versions de Python sense dificultats. Ara mateix a la meva màquina tenc el 2.4 i el 2.5 essent aquest darrer la versió per defecte. A poc a poc les distribucions l'aniran incorporant, primer com a opció i d'aquí un parell d'anys com a versió per defecte, però llavors ja no serà el 3.0, sinó el 3.x segurament.
L'important del llançament de la versió 3.0 és que a partir d'ara començarem a veure millores en el rendiment de Python 3, pel que pareix la versió 3.0 és més lenta que la 2.5, i a poc a poc s'aniran adaptant les llibreries de tercers.
Això vol dir que no fa falta frissar massa a portar totes les nostres aplicacions al 3.0. Primer convé esperar a que les nostres distribucions preferides posin la 2.6 com a versió per defecte i després anar adaptant-nos poc a poc i començar a agafar conciència dels canvis de la 3.0 per a fer que quan donem el pas gairebé tot ho faci l'script automàtic de conversió.
Traducciones/Translations by apertium
1 comentari, 0 trackbacks (URL) , Tags: Python
Formulari compost a Django
Escrit per Aaloy a 23 de November , 2008 a les 7:48 p.m.
Get the Englist translation of this post at: Gencat
Obtén la traducción al castellano de este post en: Gencat
Django té un sistema de tractament de formularis molt bo. Ens permet per una banda la reutilització de codi, ja que separa el que és la definició del formulari i la seva validació de la part de presentació.
La validació de la informació és d'allò més interessant, ja que assegura que si un camp del formulari l'hem definit com a sencer, el valor de la variable que obtindrem serà un sencer, o en cas contrari hi haurà un error de validació.
Per tot això, la idea és utilitzar el formularis de Django sempre que sigui possible i reutilitzar tot el que tinguem.
El problema es presenta quan en una plana ens n'adonam que necessitam dos formularis, no hi ha cap exemple de com fer-ho a la documentació. Veurem que una vegada solucionat el problema és tant obvi i simple que efectivament no importa documentar-ho, encara que estaria bé :)
Per a aquest exemple he posat el codi al repositori d'appfusedjango
Anem per feina
La idea és ben senzilla, crearem dos formularis i els farem servir a la nostra vista. Per a facilitar-no les coses, podem posar els dos formularis dins una llista de manera que per muntar la plana sols haurem de recorre la llista de formularis que li passam.
A l'exemple he creat dos formularis LoginForm i ContactForm, que es generaran a two_forms.html
def two_forms(request):
if request.method == 'POST':
contact_form = ContactForm(request.POST)
login_form = LoginForm(request.POST)
if login_form.is_valid() and contact_form.is_valid():
# do whatever you need as everything is valid
return HttpResponseRedirect('/thanks/')
else:
contact_form = ContactForm()
login_form = LoginForm()
forms = [contact_form, login_form]
return render_to_response('two_forms.html', {'forms': forms})
Com podem veure el funcionament és el mateix que en el cas d'un formulari normal, sols que hem crear-ne dos (o els que vulguem) i anar cridant al mètode is_valid per fer les validacions.
Això funciona perquè cada formulari agafa del post sols les dades que coincideixen amb els camps que té definits i perquè a l'hora de muntar la plana Django mira si el formulari té errors (la validació es fa tant cridant a is_valid com accedint als errors), d'altra manera i donat que Python fa servir l'avaluació curta de l'and, no tindríem els errors del segon formulari si el primer ja no validàs. Això explica el perquè hi ha aquesta doble via de llançar la validació a Django.
I això ens duu de manera natural a la següent qüestió, què passa si als formularis hi ha camps amb al mateix nom?
Doncs que Django no serà capaç d'esbrinar a quin camp correspon cada cosa in ens trobarem amb un petit problema.
Però tranquils, això està controlat, basta afegir un prefix que sigui únic per a cada formulari. Aquest prefix s'afegirà al nom dels camps que es generen per a l'HTML i d'aquesta manera en recuperar la informació Django sabrà quin camp correspon a cada formulari.
Hem de tenir cura d'assignar el prefixe tant a la part del GET com a la part de POST de la funció.
I això és tot, fàcil i net!
Observacions finals
A l'exemple de tres formularis amb el mateix nom he deixat codi de depuració, el import ipdb; ipdb.set_trace(), ho podeu llevar, levar sols la i del ipdb o bé instal·lar el ipdb, un depurador un poc més potent que el pdb de tota la vida i amb ressaltat de sintaxis.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python Django
Netbeans IDE 6.5 edició Python
Escrit per Aaloy a 22 de November , 2008 a les 11:51 a.m.
Fa no res ha sortit l'edició Early Accés de Netbeans per Python.
L'IDE integra un editor amb autocompletat de codi, depuració integrada, integració de subversion i tot el que un normalment pot esperar d'un entorn avançat de programació.
En la documentació he vist que hi ha una branca per Django, però encara no he trobat com accedir-hi. Tanmateix no té molta importància ara per ara, ja que si és un bon editor per Python ho serà per editar projectes Django.
En l'execució damunt el PPC amb la màquina virtual IBM JDK6, funciona acceptablement bé, però he tingut que variar alguns dels paràmetres d'inici per a que l'entorn no s'arrossegàs tant. Res de nou, per Ecipse també ho vaig fer, i la impressió general és que llevat els casos en que a la màquina virtual li pega per consumir el 99% de les dues CPUs, l'entorn es comporta molt bé.
El paràmetres de tunejat:
-J-Xmx356m
-J-Xverify:none
-J-XX:CompileThreshold=100
-J-XX:PermSize=64m
-J-XX:MaxPermSize=96m
-J-Djava.net.preferIPv4Stack=true
Aspectes destacats
Entorn de feina: net, molt net. Aprofita molt l'espai de treball i es deixa un gran espai per a l'editor.
El completat de codi és del milloret que he vist. A més han aconseguit extreure la documentació i presentar-la de manera poc intrussiva i elegant.
Possibilitat de crear plantilles. És una de les coses que faig amb Vim i que molts editors tenen, però que no acaben de funcionar tan bé com les de Vim. Netbeans ho fa. He portat algunes de les plantilles de Vim sense problemes.
Navegació entre objectes pitjant amb la tecla Ctrl damunt l'objecte. És un de les coses que més m'agraden d'Eclipse per Java i Netbeans també ho ha incorporat a Python.
Neteja de imports innecessaris. Ens deixa el codi més net.
Tecles ràpides per gairebé totes les opcions. Per mi és important que allò que faig habitualment permeti ser executat sense tenir que llevar les mans del teclat.
Possibilitat de crear les nostres pròpies plantilles.
L'eina de gestió de diferències entre fitxers manté el l'acoloriment de sintaxi. Una gran millora respecte a tot el que hi ha. És una eina fantàstica.
Punts a millorar
L'autocompletat té un preu: l'inici del programa és lent ja que parseja tot el que troba. Si teniu l'opció del la finestra de tasques activada la cosa pot arribar a ser insuportable. Afortunadament si posam que sols ens mostri les tasques de l'editor actiu la cosa millora. Tot i així crec que falta algun tipus de configuració per poder definir per projecte les llibreries que s'utilitzaran i les que no per agilitar-ne el parseig i evitar que algunes vegades a l'autocompletat surtin cents d'opcions que no tenen res a veure amb el projecte.
La integració amb subversion és bona, però la interfície de selecció del que s'ha de pujar i del que no és molt farragosa, ja que s'ha de seleccionar element a element amb un desplegable.
Pareix haver hi un error quan es selecciona una plantilla, ja que sols te deixa triar les de Python i Others. Es posa tot allà dintre i ja està, però sorprèn.
Refactorització. La que té Eric4 amb Rope o la de pyDev mateix permeten més opcions.
Hi ha un bon grapat de coses que vull explorar com són les macros, la inserció de codi i mirar més a fons el comportament de les plantilles, crec que se n'hi pot treure molt de suc.
Com a conclusió dir que m'ha agradat molt aquest entorn. Potser estic molt condicionat a que ha funcionat força bé en el PPC, però en la meva opinió és un entorn fantàstic per al desenvolupament de Python en general i de projectes Django en particular.
El faré servir una temporada, sols hi duc dos dies, a veure si tot confirma ser tant bo com sembla i puc trobar com instal·lar la branca per Django. Això sí, el vim seguirà essent un dels meus principals entorns de desenvolupament: quan un ha de fer modificacions de codi ràpidament o treballar per ssh no hi ha res millor. Sempre serà o bé una eina principal o complementària. Sempre és bo tenir dos editors de capçalera.
Traducciones/Translations by apertium
3 comentaris, 0 trackbacks (URL) , Tags: Python Django
El django-admin no és per fer aplicacions d'usuari final
Escrit per Aaloy a 15 de November , 2008 a les 10:24 a.m.
Quan la gent dóna les seves primeres passes amb Django sovint queda enlluernada pel django-admin, una aplicació Django que ens permet definir un gestor de les nostres aplicacions, de manera que podem gestionar els usuaris, donar-hi permisos, gestionar les bases de dades, etc.
Hi ha que dir que l'aplicació està molt ben feta i es pot configurar moltíssim: indicar quins camps s'han de visualitzar, per quins camps es cercaran, fins i tot posar-hi javascript o modificar-ne l'aparença per a que la nostra aplicació faci el que nosaltres volem.
Aquesta facilitat però, té un perill, la gent té tendència a pensar que Django serveix per fer aplicacions web amb l'admin, que la seva aplicació ha de ser l'admin, així que recordem-ho:
El django-admin no és per fer aplicacions d'usuari final
Django admin fa molta màgia per dintre i aquesta màgia es basa en convencions que s'apliquen als models i a la definició del ModelAdmin, i aquestes convencions fan que per una part pugem tenir un gestor per a la nostra aplicació en quatre potades, però per altra, que si volem fer alguna cosa que surti del que està definit i establert ens durà molta feina.
La millor manera d'encarar-ho és tenir molt clar per a què serveix l'admin i per a què no:
Manteniment de les nostres taules de configuració i mestres? sí. Normalment ens anirà fantàstic per això i a meś ho podem tenir molt ràpidament. És ideal en les primeres etapes del desenvolupament, ja que es pot donar a l'usuari per a que carregui dades de prova i ja veu com pot funcionar l'aplicació.
Com a gestor web de la nostra base de dades? També anirà molt bé. Podem mapejar les taules i els camps que volem administrar, fer cerques, filtrar, editar i esborrar.
Com a eina d'usuari final per a que pugui configurar l'aplicació? Sí, si aquesta sols implica operacions senzilles, per exemple l'edició d'una plana web, afegir registres a una taula, etc. Podem definir quines taules pot tocar cada usuari i definir-ne perfils.
Com a eina d'usuari final on l'aplicació té molta lògica de negoci o bé un fluxe complex. NO. Millor començar un gestor pel nostre compte. Fer formularis CRUD amb Django és molt senzill i encara que pareix que dupliquem el que hi ha al django-admin, aquesta feina extra es veurà compensada a l'hora de definir els fluxs més complexos, ja que tindrem tota la potència de Python i Django al nostre abast i no estarem limitats a les convencions i funcionament del Django admin.
Les coses funcionen molt millor quan s'utilitzen per allò que estan pensades.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python Django
Rapid GUI Programming with Python and Qt
Escrit per Aaloy a 10 de November , 2008 a les 12:30 a.m.
El divendres vaig rebre un nou llibre:
Rapid GUI Programming with Python and Qt
Editorial Prentice Hall
Autor: Mark Summerfield
ISBN: 978-0-13-235418-9
Es tracta d'un manual de programació per al desenvolupament d'aplicacions amb Python i les Qt.
Me l'he estat fullejant i la veritat és que sols amb la qualitat de l'edició el llibre promet.
El primers capítols duen una petita introducció a Python, que segurament servirà a la gent que s'atraqui al món del la programació d'aplicacions d'escriptori portables, cercant quelcom més senzill de fer anar que la programació en C++.
L'estructura s'orienta per temes, on es van construint aplicacions de diferents nivells de complexitat i es complementa el tema amb tot un seguit d'exercicis per a que el lector faci feina pel seu compte.
Els que ens dedicam fonamentalment a la programació web, sovint tenim tendència a pensar que l'escriptori clàssic no té sentit, i això no és cert. Ara per ara encara hi ha força aplicacions i entorns on una aplicació d'escriptori pot solucionar millor els problemes al nostre client que una aplicació web. Poder oferir una solució feta amb Python amb una llibreria com Qt4 (no oblidem tampoc les WxPython) sens dubte ens serà de profit per ambdues parts.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Llibres i revistes Python
Senyals a Django
Escrit per Aaloy a 03 de November , 2008 a les 8:35 p.m.
El mecanisme de senyalització de Django ens permet desacoblar les nostres aplicacions, ja que permet notificar d'accions que es produeixen a tot una sèrie de receptors o subscriptors d'aquestes senyals.
Podem distingir dos tipus de senyals a Django:
Les senyals que venen predefinides a bastiment i que podem trobar a la documentacio de Django. En aquest cas Django se n'encarrega de llançar l'avís de que una acció concreta s'ha produït i nosaltres com a programadors podem generar codi per tal de subscriure'ns a aquest tipus de missatges i disposar-ho tot per a que s'executi el codi que ha de respondre a aquestes accions.
Les senyals definides per l'usuari. Es un cas més general que l'anterior. Django ens permet definir les nostres pròpies senyals i enviar-les. En aquest cas doncs, podem definir tant la senyal com el tractament que se'n faci.
Escoltant senyals
Per a escoltar una senyal necessitam fer dues coses:
Definir la funció que rebrà la senyal amb el codi que s'ha d'executar.
Connectar la funció amb la senyal, és a dir subscriure's a la senyal.
Les funcions que haurem de definir han de ser de la forma:
def nom_funcio (sender, kwargs): "Aqui va la documentacio" # aqui el codi pass
Hem de tenir en compte que el nombre d'arguments que pot transmetre una senyal per definició pot canviar en qualsevol moment. Els arguments es passen per nom, i la nostra funció ha d'estar preparada per gestionar aquest possible canvi d'arguments.
Per a connectar la senyal amb la nostra funció importarem la senyal a la que ens vulguem subscriure i ens hi connectarem amb el mètode connect de la pròpia senyal.
Per exemple per connectar-nos a la senyal que s'emet quan una petició http ha acabat bastaria fer:
from django.core.signals import request_finished request_finished.connect(nom_funcio)
Les senyals tenen un paràmetre per defecte, el sender, que ens permet subscriure'ns sols a aquelles senyals que provenguin d'instàncies d'una classe determinada.
Definint les nostres senyals
Per a definir les nostres senyals hem fer dos passos:
Definir la senyal i els arguments que passarà
Allà on ens interessi enviar la senyal amb els arguments que hem definit
Pel primer pas basta importar django.dispatch i crear una instància de Signal amb els paràmetres que hem definit.
import django.dispatch pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])
Enviar la senyal és encara més senzill, basta cridar al mètode send amb els paràmetres que hem definit, sense oblidar-nos d'establir la variable sender amb l'objecte que ha enviat la senyal.
Suposem que volem que el sistema ens avisi automàticament cada cop que algú esborra un usuari de la base de dades.
Per a mostrar-ho farem ús del senyal pre_delete que es troba a django.db.models.signals. Per al registre crearem una taula a la BD que guardarà l'usuari que se va esborrar i el seu nom.
La senal pre_delete s'envia quan s'entra dins el mètode delete del model, com a arguments té el sender que és la classe que envia la senyal i instance que recull l'objecte que s'eliminarà de la base de dades.
Nosaltres ens volem registrar sols a les senyals que impliquin eliminar usuaris de l'aplicació, així que sols ens subscriurem a les senyals que provenguin de django.contrib.auth.models.User
El nostre model seria
#!/usr/bin/env python # -*- coding: UTF-8 -*- # Autor: aaloy from django.db import models from django.contrib.auth.models import User from django.db.models.signals import pre_delete class Eliminat(models.Model): user = models.CharField(max_length=30) created = models.DateTimeField(editable=False, auto_now_add=True, blank=False, db_index = True) def __unicode__(self): return self.user def registra(sender, **kwargs): instancia = kwargs['instance'] usuari = Eliminat(user=instancia.username) usuari.save() pre_delete.connect(registra, sender=User)
Per a veure com podem utilitzar les nostres pròpies senyals, crearem una senyal que registrarla la IP i el nom de la vista.
Per això crearem una nova classe, per exemple LogIp, que mantindrà el registre i connectarem el senyal amb la funció registre_ip
Hem de tenir en compte que es un exemple acadèmic, té poc sentit fe aquest tipus de coses, és a dir, definir una senyal dins el mateix model i enviant-la a la vista. Té molt més sentit que el senyal s'envii en resposta a una acció dins el propi model o a una acció particular de la vista i que una aplicació externa s'hi subscrigui.
class LogIp (models.Model): "Logs the ips and calling functions" name = models.CharField(max_length= 200) ip = models.IPAddressField() created = models.DateTimeField(editable=False, auto_now_add=True, blank=False, db_index = True) in_view = django.dispatch.Signal(providing_args=['ip', 'name']) def registra_ip(sender, **kwargs): ip = kwargs['ip'] name = kwargs['name'] log = LogIp(name= name, ip=ip) log.save() in_view.connect(registra_ip)
in_view és la nostra senyal, com a paràmetres hem posat ip i name, això vol dir que la funció que es registri com a escoltadora els pot fer servir i ha de ser capaç de admetre'ls. Per una altra banda també ens diu que allà on enviem la senyal amb el send haurem de proporcionar també aquests paràmetres.
Si llançam el senyal a la vista quedaria com
def list(request): "Lists the deleted users" deleted = Eliminat.objects.all() in_view.send(sender=chivato.views.list, ip=request.META['REMOTE_ADDR'], name=request.get_full_path()) return render_to_response('list.html', {'deleted':deleted})
Amb això cada cop que algú des de el seu navegador accedeixi a la funció quedarà registrada la url d'accés i la seva ip.
Tot el codi font amb un projecte complet llest per funcionar, sols heu de canviar las rutes al properties.py a appfuse o directament
svn checkout http://appfusedjango.googlecode.com/svn/trunk/signals
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python Django
CMS i Django
Escrit per Aaloy a 02 de October , 2008 a les 9:09 p.m.
Llegit un apunt d'Okkum m'ha fet pensar en el joc que ens poden donar els CMS en el desenvolupament web i en els perills que també comporten.
De CMS n'hi ha en gairebé qualsevol llenguatge i bastiment que tengui una mínima orientació cap a la web, ja que al cap i a la fi es tracta de facilitar que l'usuari que ha de crear els continguts de la web ho tengui fàcil per fer-ho, i que les limitacions que imposa el CMS facin que tota la web tengui una estructura comú (afegiu-hi aquí la paraula corporativa).
Per PHP i Java n'hi ha per avorrir de CMS, per Python també n'hi ha un bon grapat, però si me'n tengués que quedar un per les possibilitats que té i la funcionalitat que aporta se'ns dubte em quedaria amb Plone.
De totes maneres, l'apunt no vol ser una comparativa de CMS, sinó reflexionar damunt les seves utilitats i els seus perills. Una web que és bàsicament contingut té en un CMS l'aplicació ideal. Si ho volem fer amb Django actualment hi ha dues possibilitats que destaquen:
Django cms alliberat recentment i que és un complet sistema de publicació de continguts.
Django page cms una aplicació per Django, és a dir pensada per a integrar-se amb un projecte web.
Cada un d'aquests projectes representa una manera d'entendre els CMS. El primer imposa que el CMS sigui l'aplicació principal i que en tot cas les funcionalitats que es vulguin afegir s'hi facin a partir del que el CMS ofereix, amb més o manco passibilitats d'integració. Pot anar molt bé si la única cosa que hem de fer és posar un formulari, però pot ser un maldecap si volem construir-hi la nostra aplicació web.
El Django page cms, per contra, suposa que serà una aplicació més a l'ecosistema del projecte, i per tant està pensant per integrar-se en qualsevol projecte. En contra té menys funcionalitat de CMS, menys cosa feta que l'anterior.
L'elecció d'un camí o un altra dependrà de l'aplicació i del client. Si hi ha o hi pot haver funcionalitat més enllà de la gestió de continguts és millor anar cap a una solució integrable que cap a una solució de CMS pura. Si els nostres usuaris no saben el que volen ni cap a on ha d'evolucionar la web doncs el sistema de component també és recomanable. Per webs de contingut que s'han de gestionar i mantenir ràpidament, el CMS pur és ideal.
I si el vostre negoci depèn del CMS, doncs no ho dubteu gaire: Plone, a anys llum de qualsevol CMS obert o tancat, i és també Python.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python
Llista de llenguatges de programació que conec
Escrit per Aaloy a 09 de September , 2008 a les 8:40 p.m.
En Corey Goldberg escriu al seu blog damunt la llista de llenguatges de programació que coneix, amb la qual cosa ha iniciat un memme? ;)
La cosa està en llistar els llenguatges de programació en el que un se n'ha desfet en un moment o altre de la seva vida. És a dir, no val dir que un coneix el llenguatge Petito si no ha passat de "hello world".
En el meu cas i per ordre cronològic
- GW-BASIC
- Turbo Basic/Quick Basic
- Assembler 8086
- Shell
- FORTRAN
- Pascal
- Icon
- Matlab
- Modula 2
- Object Pascal (Delphi)
- SQL
- Python
- Forté
- C
- VbScript
- Java
- Javascript
Ja no es podríen classificar com d'haver fet res seriós:
- Fast (un llenguatge que generava .com especialitzat en fer jocs).
- Lisp
- C++
- Groovy
- Ruby
- C#
El Deplhi és un dels llenguatges que més he disfrutat de programar, però em vaig cansar de les tonteries de Borland i vaig trobar Python, quina gran troballa! Des d'aleshores no l'he deixat mai al Python, encara que altres llenguatges també s'han anant fent el seu lloc, el Python sempre ha estat en primera línia, encara que fos per generar codi per altres llenguatges.
Traducciones/Translations by apertium
1 comentari, 0 trackbacks (URL) , Tags: Informàtica Python
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 | Directory | SLOC-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
AppfuseDjango actualitzat a la versió de Django
Escrit per Aaloy a 16 de August , 2008 a les 11 a.m.
Avui he actualitzat AppfuseDjango per a que funcioni amb la darrera versió de Django.
Darrerament hi ha molts canvis a Django, ja atracant-se a la versió 1.0, i alguns d'ells són incompatibles amb les versions anteriors.
La idea de l'aplicació és que servesqui de punt de partida per altres aplicacions i com a codi de mostra per a la gent que està començant amb Django. El tutorial de Django està força bé per començar, però després, quan has de fer una aplicació amb manteniments, internacionalització, etc. es queda un poco curt. No hi ha res a dir, l'objectiu del tutorial és ensenyar i el d'una aplicació com AppfuseDjango l'objectiu és ser un punt de partida.
De fet ja fa estona que no faig servir la utilitat de Django per a crear projectes i aplicacions, el que faig és fer un export d'AppfuseDjango i començar a partir d'allà.
Pels qui us demaneu què s'hi pot trobar:
- Un manteniment CRUD: llistat, alta, baixa i modificació d'un registre.
- Exemple de paginació
- Mostra com internacionalitzar una aplicació.
- Un exemples de com fer anar l'Ajax i json amb extjs i jqgrid
Però el més important crec que no és tant el codi que es mostra sinó que es vegi l'organització d'un projecte.
Veureu que s'ha tret la configuració del settings.py cap a un properties.py, que no trobareu al codi, sinó que hi ha un properties.py.template. Això es fa per deixar l'aplicació preparada per l'entorn de producció i per a ser utilitzada per molts desenvolupadors. Fent-ho així, poden tenir distintes configuracions per a cada un dels desenvolupadors i com que són pròpies de cada un estan fora del control de versions de l'aplicació. Tanmateix sols és cosa de copiar el properties.py.template i modificar-ho per a adaptar-ho a les nostres necessitats (directori, caché, etc.).
Una altra cosa que he anat posant són algunes optimitzacions i hacks útils trobases pels fòrums o de collita pròpia. Entre elles una que ens permet tenir una caché de plana que depèn de l'idioma de visualització, és a dir, es genera la clau de la caché amb l'idioma de l'usuari.
Com a darrera incorporació, un mètode molt elegant d'editar i inserir registres que fa ús de l'avaluació pererosa en Python, trobat a themorgue.org, el codi ha quedat molt net, potser una mica menys entenidor que abans, però l'estalvi en línies de codi ho compensa.
Els plans futurs crear branques amb distints tipus de projectes per assolir l'objectiu de tenir el punt de partida bàsic per a cada tipus d'aplicació: html pura, html amb ajax, RIA, etc. i així sols tenir que baixar l'estrictament necessari en cada cas.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python Django
Unit tests
Escrit per Aaloy a 25 de July , 2008 a les 6:10 p.m.
Supòs que no he de convèncer ningú de les bondats dels tests unitaris a l'hora de desenvolupar.
Encara que no arribem als extrems que proposa la gent que fa "test driven development" tenir tests ajuda a l'hora de provar les aplicacions:
- Queda constància del que s'ha provat
- Les proves són repetibles
- Es poden anar afegint noves proves quan es detecten noves situacions i/o errors.
- Ens ajuden a la refactorització, ja que ens ajuden a comprovar que la refectorització no ha variat el funcionament del programa.
El clàssic en test unitàris per Python és PyUnit que segueix una aproximació diguem-ne ortodoxa, és a dir, basada en crear una classe que extén TestCase i a partir d'aquí anar agrupar els tests en el que s'anomena una TestSuite.
Una altra aproximació ben diferent és la de doctest, aquí el que tenim és que s'escriu el codi de testeig i la serva sortida dins de la mateixa aplicació, no hi ha API però sovint pot resultar un tant confús.
Finalment tentim un nouvingut (relativament, que ja té uns anyets) el py.test, que ve avalat per la gent de PyPy i que va ser creat per a testejar el desenvolupament de l'intèrpret de Python fet en Python.
En Grig Gheorghiu's té un conjunt de tres articles comparant unittest, doctest i py.test, encara que són un poc antics, en temps Internet, crec que ajuden molt a veure les principals mancances i avantatges de cada un.
Per suposat, hi ha molts més a sistemes de testeig, podeu trobar-ne una recopilació a Python Testing Tools Taxonomy
He estat gairebé una setmana desenvolupant i fent tests amb py.test, i he de dir que m'ha agradat, és molt més còmode de fer anar que cap dels altres. Basta que creis un mètode que comenci amb test_ o acabi en _test i ja ho tenim llest per ser provat, que passi el test o no sols es cosa de que hi hagi un asssert que retorni vertader si ha passat un testo o fals si no l'ha pasat.
Una de les característiques que m'han agradat més és la possibilitat de desactiva ràpidament un test amb disabled = True on el valor es pot substituir per una condició, amb la qual cosa podríem fer que un test s'executàs o no en funció de l'avaluació d'una condició, per exemple, si detectam que estam a l'entorn de producció no borrar la base de dades!
I també he trobat molt còmode l'opció de poder establir condicions d'inici i acabament per tot un mòdul, això m'ha permés per exemple, obrir una sessió i mantenir la connexió i el identificador de sessió per a tots els tests, tancant la sessió sols quan tots els tests ja han acabat.
La part que m'ha xocat és la manera de testejar les excepcion, ho fan amb
py.test.raises(Exception, func, *args, **kwargs)
py.test.raises(Exception, "func(*args, **kwargs)")
És a dir, s'ha d'importar el mòdul py i cridar a py.test.raises, després posarem l'excepció que volem tractar, la funció que s'ha de testejar i que genera aquesta expepció i seguidament els paràmetres que té la funció.
Crec que això ha estat la única cosa més complicada d'aprendre. La resta és tot ben natural.
Me falta provar la part de distribució de tests, però per ara crec que va camí de convertir-se en la meva eina de testeig Python de referència, a l'espera, això sí, de veure com ho puc integrar amb Hudson.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python
A voltes amb els trackbacks
Escrit per Aaloy a 22 de July , 2008 a les 8:01 p.m.
Benvolguts amics, coneguts i saludats,
Aprofitant la calor, la benentesa, i la moguda de Django estic aprofitant per retocar el sistema de trackbacks del blog.
Estic abusant un poc de la confiança i fent proves a altres blogs a més del meu, per veure si hi ha problemes.
Si veis alguna cosa rara, trackbacks que venen de trespams amb poc sentit o antics, perdonau-me, estic abusant de la vostra confiança i amabilitat. Procuraré no fer massa destrossa, i no cal dir-ho, esborrau el que convingui.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python Django
Benchmark: mako i lmxl
Escrit per Aaloy a 13 de July , 2008 a les 9:20 p.m.
Estam plantejant fer una remodelació de la web B2B que tenim, ara està feta en Java i aprofitant la remodelació la meva intenció ( si me deixen clar), és aprofitar que la remodelació és força important per a reescriure el codi en Python i Django. Si fos un canvi petit no m'ho plantejaria, però és un canvi que pot dur mesos de feina i en aquest cas refer-ho amb Python suposa no allargar els temps de desenvolupament, encara que la feina global en termes de funcionalitat sigui més gran.
Però tampoc és cosa de tirar-se a la piscina, i abans de res convé saber amb què ens trobarem. Un dels aspectes més crítics és que hem de consumir un servei web en format xml sobre http. Cap problema, urllib per exemple és capaç de fer tot això i molt més, la cosa està en poder generar els xml i consumir-los en molt poc temps.
Aquest cap de setmana m'he entretingut fent un petit benchmark [1], volia comprovar una hipòtesis: fer servir un llenguatge de plantilles per generar les peticions xml i un parsejador per a consumir l'xml que m'arribarà. L'altra opció es generar les peticions directament amb la llibreria de parseig.
La primera opció té com avantatges que s'ha d'escriure menys codi i que queda força documentada la petició en sí. La segona te l'avantatge de que que sols fas servir una llibreria. Així doncs el que ha de dir la darrera paraula és el factor rapidesa. Serà més ràpida la llibreria de plantilles o la de l'xml?
Primer presentarem els candidats: per una part mako, un llenguatge de plantilles que surt molt ben parat a les comparatives de velocitat i de l'altra lxml una interfície Python damunt unes de les llibreries per tractar xml més ràpides del mercat libxml2 i libxslt.
Per fer les proves tirarem de les dades que representen els cotxes que he tingut:
VEHICLES = {'seat': {'id': 1, 'color':'blanc', 'preu':150000},
'ax' : {'id': 2, 'color':'blanc', 'preu':1100000},
'505' : {'id': 3, 'color':'blanc', 'preu': 500},
'saxo': {'id': 4, 'color':'blau', 'preu':1500000}
}
El que farem és generar un xml que representi aquesta estructura de dades. Com que tant amb mako com lxml la cosa va força ràpida, farem 10.000 repeticions.
El codi per mako és
from mako.template import Template
template = """
<vehicles>
% for marca, desc in vehicles.items():
<vehicle id = "${desc['id']}">
<marca>${marca} </marca>
<color>${desc['color']} </color>
<preu>${desc['preu']} </preu>
</vehicle>
% endfor
</vehicles>
"""
plantilla = Template(template)
for i in xrange(1, REPETICIONS):
xml = plantilla.render(vehicles=VEHICLES)
El que feim és compilar la plantilla un pic, per simular les condicions reals, ja que en una aplicació en producció és el que faríem, i renderitxar l'xml amb les dades fins al nombre de repeticions desitjat.
Per lxml la cosa és semblant, sols que el codi (si no tenim en compte la definició de la plantilla) és una mica més llarg
from lxml import etree
for i in xrange(1, REPETICIONS):
root=etree.Element( 'vehicles' )
for marca_vehiculo, desc in VEHICLES.items():
vehicle = etree.SubElement(root, 'vehicle', id = str(desc['id']) )
marca = etree.SubElement(vehicle, "marca" )
marca.text = marca_vehiculo
color = etree.SubElement(vehicle, "color" )
color.text = desc['color']
preu = etree.SubElement(vehicle, 'preu')
preu.text = "%.0f" % desc['preu']
xml2 = etree.tostring(root, pretty_print=False)
També en aquest cas procuram que hi hagi igualtat de condicions, i hem posat el pretty_print a False de manera que l'xml generat no estarà ben tabulat i no quedarà tan elegant com el el cas de mako, però també és el que faríem en un entorn de producció.
I ja està, ara sols falta executar-ho i mostrar-ne els resultats:
| Repeticions | mako | lxml |
| 100 | 0,0761 s | 0.0277 s |
| 1.000 | 0,2897 s | 0.2823 s |
| 10.000 | 2.3076 s | 2.8906 s |
D'això en treim dues conclusions:
- Que ambdues aproximacions són molt ràpides en la generació de l'xml.
- Que mako s'aprofita molt bé de la precompilació de les plantilles. En el benchmark he considerat que es compilava un pic i després s'executaven les repeticions. Si no consideram el temps de compilació
| Repeticions | mako | lxml |
| 100 | 0,0201 s | 0.0277 s |
| 1.000 | 0,2079 s | 0.2750 s |
| 10.000 | 1,9888 s | 2.9513 s |
És a dir, que si feim sempre feina amb el mateix tipus de peticions, l'opció de fer servir mako per a generar les peticions xml, compilant les plantilles a l'inici de l'aplicació és té un rendiment molt millor que generant l'xml cada cop amb l'lxml.
Per cert, les proves estan fetes amb Ubuntu Linux corrent en un PowerPC de doble processador de 2 GHz, és a dir, res de l'altre mon.
[1] Sí, ja ho sé, no m'hauria d'endur feina a casa
Traducciones/Translations by apertium
2 comentaris, 0 trackbacks (URL) , Tags: Informàtica Python
Protocol Buffer
Escrit per Aaloy a 08 de July , 2008 a les 10 p.m.
Protocol Buffer és una llibreria d'intercanvi de dades que Google ha alliberat i que segons promet és de 20 a 100 vegades més ràpida que l'XML (i ja no parlem de SOAP) per a l'intercanvi de dades entre aplicacions.
Lo de la velocitat s'haurà de comprovar, però el que sí pareix clar és que és prou senzilla per ser abastable, la documentació és bona, i ja va dirigida als tres principals llenguatges de programació (C++, Java i Python).
Com que en faig servir dos habitualment, doncs es cosa de fer-hi una ullada i algunes proves d'stress a veure si realment és tant ràpida com diuen.
La cosa no sé si s'imposarà com a format d'intercanvi entre llocs d'Internet, però el que sí tenc clar és que si és més ràpid pot ser ideal com a format per a tecnologies SOA dins de la mateixa empresa. Una reducció d'un factor 10 ja seria prou bona, amb l'avantatge de que es podrien crear (com ara, per cert) serveis en un llenguatge i consumir-los en un altre, però sense tenir que pagar el preu que suposa en termes de rendiment fer-ho en format WSDL.
Es prest, per donar-ne una opinió amb més fonament, però pel que he vist de la documentació i els exemples, crec que aquest format i jo ens durem bé :)
Traducciones/Translations by apertium
2 comentaris, 0 trackbacks (URL) , Tags: Informàtica Python Java
Sigues dinàmic
Escrit per Aaloy a 29 de June , 2008 a les 3:53 p.m.
L'altra dia vaig fer un petit prototip per veure amb quines dificultats em trovaba a l'hora de connectar amb Python contra l'LDAP de l'empresa (un Notes) i contra l'Active Directory. Aquesta funcionalitat ja la tenia desenvolupada en Java, però com que l'aplicació que estava plantejant es faria amb Python, vaig començar a mirar els tempes més problemàtics: l'autentificació i com imprimir els pdfs.
La connexió amb l'LDAP i la funcionalitat que volia, per tal d'obtenir tota la informació del l'usuari que es connectava no va ser gens problemàtica, en total 76 línies de codi davant les 350 llargues de Java, o el que és el mateix en Python vaig haver d'escriure un 80% menys de línies per a tenir la mateixa funcionalitat. D'això no poden concloure que sempre els programes en Python seran un 80% més curts, però és una evidència més del que parlam quan deim que s'escriu molt menys codi i que és més ràpid fer-ho.
El perquè en aquest cas concret, dóna peu a aquest apunt, presentarem la manera de tractar amb Python dues situacions bastant comuns quan ens hem de connectar a altres sistemes o fer servir llibreries de tercers: la transformació de diccionaris en objectes i el com tractar el cas en que tenim múltiples paràmetres opcionals.
Diccionaris a objectes
La situació és la següent: tenim un diccionari que volem passar com a paràmetre i fer servir les seves claus com si fossis propietats de la classe, de tal manera que si una clau no existeix ens dóni el valor per defecte.
Aquesta situació me la vaig trobar connectant a l'LDAP. La llibreria de Python en interroga l'LDAP torna un diccionari i volia que aquest diccionari formàs part de la classe Usuari que havia de contenir tota la informació de l'usuari que s'estava connectant a l'aplicació.
Suposem doncs que el diccionari que ens retornen és:
dades = {'nom': 'Antoni Aloy',
'telefon': '555 55 55 55',
'localitat': 'Binissalem',
'email': 'aaloy@example.com',
'blog': 'http://trespams.com'
}
El que volem és posar tota aquesta informació dins una objecte de tipus Usuari de tal manera que sigui fàcilment manipulable i entendible. És a dir, que puguem fer usuari.telefon,
class Usuari:
"Exemple de com transformar les claus d'un diccionari en propietats"
def init(self,ldap_prop = dict()):
self.__propietats = ldap_prop
def __getattr__(self, name):
"Obtenim l'el valor de la propietat del diccionari"
try:
return self.__propietats[name]
except:
return "No assignada"
def __str__(self):
"Representació textual de l'usuari"
return "%s - %s" % (self.nom, self.email)
def propietats(self):
"Retorna la llista de propietats"
return self.__propietats.keys()
Ho podríem fer servir amb el codi següent:
if __name__ == "__main__":
u = Usuari( ldap_prop = dades)
print "Nom %s" % u.nom
print "Telefon %s " % u.telefon
print "Provincia %s " % u.provincia
print u
El nostre cas era prou senzill, si volem quelcom més complexe podem anar a a una recepte de Michael Foord, on podem veure com s'extén l'objecte diccionari per a fer el mateix que hem fet en el nostre exemple i a més permetre la utilització de paràmetres normals.
Parametrització
Tenim una classe amb una gran quantitat de paràmetres que es poden modificar. Per defecte tots aquests paràmetres tenen un valor per defecte. Volem que l'usuari pugui actualitzar els valors i obtenir-los. A més hi pot haver paràmetres que són sols de lectura.
Aquesta situació me la vaig trobar instanciant classes de Reportlab. A l'hora d'utilitzar la llibreria ens trobam en aquesta situació: tenim una gran quantitat d'atributs que podem assignar, però la major part del temps els valors per defecte ja ens estan bé. Vegem com ha resolt la situació la gent de Reportlab:
class BaseDocTemplate:
"""...."""
_initArgs = { 'pagesize':defaultPageSize,
'pageTemplates':[],
'showBoundary':0,
'leftMargin':inch,
'rightMargin':inch,
'topMargin':inch,
'bottomMargin':inch,
'allowSplitting':1,
'title':None,
'author':None,
'subject':None,
'keywords':[],
'invariant':None,
'pageCompression':None,
'_pageBreakQuick':1,
'rotation':0,
'_debug':0}
_invalidInitArgs = ()
def __init__(self, filename, **kw):
"""create a document template bound to a filename (see class
documentation for keyword arguments)"""
self.filename = filename
for k in self._initArgs.keys():
if not kw.has_key(k):
v = self._initArgs[k]
else:
if k in self._invalidInitArgs:
raise ValueError, "Invalid argument %s" % k
v = kw[k]
setattr(self,k,v)
p = self.pageTemplates
self.pageTemplates = []
self.addPageTemplates(p)
...
A l'hora de crear la classe BaseDocTemplate els atributs es defineixen dins un diccionari _initArgs, a la inicialització de la classe l'únic paràmetre obligatori és filename, però perfectament podem fer
myTemplate = BaseDocTemplate(filename="test.pdf", showBoundary=1, author="aaloy")
A l'init el que fa es repassar-se tots els atributs que hem definit al diccionari, si els paràmetres que s'han passat no coincideixen amb la clau del diccionari es crea un nou atribut a l'objecte amb el valor que té al diccionari (el valor per defecte). En canvi si hi és, verifica primer que no sigui un paràmetre de sols lectura, comprovant-ho a _invalidInitArgs i en cas que no ho sigui crea l'atribut amb el valor que li passam com a paràmetre en lloc del valor per defecte que té definit al diccionari.
D'aquesta manera ens permet utilitzar i assignar valor molt fàcilment i sols inicialitzar allò que necessitam.
La quantitat de codi que ens estalvien aquests deus receptes és proporcional al nombre d'atributs que tengui la nostra classe si la fessin en un llenguatge de programació no dinàmic.
Traducciones/Translations by apertium
4 comentaris, 0 trackbacks (URL) , Tags: Python
La meva experiència amb Django
Escrit per Aaloy a 22 de June , 2008 a les 12:03 p.m.
En Maties Bonet ens va escriure un e-mail a mi i a Guillem demanant-nos per la nostra experiència en l'ús de Django.
Amic Maties, bona cosa has demanat! Pepara't perquè aquest apunt pot ser llarg :)
La meva relació seriosa amb Django ja té més de dos anys, és difícil estimar la data, però si en tingués que donar una seria la del 3 d'agost del 2006, data del primer commit del major projecte que hem fet amb Django fins ara,amb actualment més de 12.000 línies de codi
Aquest projecte inicialment estava desenvolupat en PHP, però necessitàvem més funcionalitat i essent les nostres filies més tendents cap al Python que cap a altra cosa, començarem a investigar els bastiments que començavent a surgir. Cercàvem quelcom que permetés una bona escalabilitat, facilitat de desenvolpament i una separació molt clara entre codi i capa de presentació. A més una de les restriccions inicials era que el servidor que tenia que dur tot això no havia de ser massa potent, un host virtual baratet hauria de ser suficient per començar.
Amb Juan avaluarem un grapat d'opcions. Anàvem mirant frameworks i en discutíem els avantatges i inconvenients. Férem una ullada a Pylons, a TurboGears i alguns altres, fent algun prototip i discutint-ne els resultats.
TurboGears estava força bé, i Pylons representava gairebé l'estat de l'art en quant a integració de componentes, però Django tenia una avantatja per a nosaltres fonamental: la seva integració entre els distints components (integració que a més no compromet a res), una documentació fantàstica i el ser un bastiment que s'havia fet servir en projectes grans, en projectes que estaven funcionant. Es podria dir que no era sols una idea sinó que el funcionament del framework era una realitat.
Així doncs ens decidirem per Django. Mesos després Guido Van Rossum com el framework que li agradava més. Un any i mig després veuríem Django com un bastiment suportat per Google. Això vol dir que tenim bon ull per les tecnologies? Segurament, però vist en perspectiva l'elecció de qualsevol dels altres dos bastiments també ens hauria anat força bé.
Django, però té aquell quelcom que et fa sentir content i satisfet amb la programació que fas. És entenidor i abastable i quan t'enfrontes a un problema de la vida real trobes que hi ha una solució en Django, per una raó molt senzilla: el bastiment es va crear per resoldre problemes de la vida real, com una resposta a la necessitat que tenien els seus creadors de tenir un bastiment que els proporcionàs una gran rapidesa en el desenvolupament i al mateix temps una gran escalabilitat.
Una vegada vàrem veure la potència del bastiment, junt amb la potència de Python i ho compararem amb el que teníem i feiem en Java, el pas següent va ser lògic: utilitzar el que sabíem en la feina diària per a l'empresa per la qual treballàvem, una multinacional del turisme. Sense deixar Java del tot, ara podíem incorporar una nova eina que ens permetria poder desenvolupar webs a la velocitat que li agradava al negoci.
Posar Django i Python a una empresa molt tradicional no és senzill, "aquest tipus de la web sempre fent coses rares!" Però l'evidència s'imposa i amb un poc de ma ampla del nostre director d'informàtica anterior començarem a fer els nostres primers projectes amb Django per a l'empresa. És una tasca que avui en dia encara costa. Quant més consultors externs té l'empresa més difícil és aquesta tasca. Aquests suposats experts no tenen idea de què és Django i de les seves possibilitats, i tampoc els convé, ja que després de la consultoria hi sol haver un desenvolupament i com que el desenvolupament és més ràpid i ells cobren per hores, doncs que no convé gaire. Però això és una altra història i també serà un altra apunt.
Actualment doncs, feim/faig servir Django i Python en quatre grans tipus de projectes:
- projectes on no s'ataca a la base de dades "legacy" de l'empresa, sinó que s'han desenvolupat des de zero.
- projectes on hi ha una gran part de continguts i a més lògica de negoci senzilla.
- projectes que consumeixen web services en SOAP que estan a la seva vegada desenvolupats en Java.
- el nostres projectes particulars, com aquest blog.
Els resultats són molt bons, un exemple: fa dues setmanes ens telefonaren del dimecres per a un projecte crític, s'havia de crear una web completa per a un client que havia d'estar llesta el divendres al matí de la mateixa setmana. El dimecres horabaixa en tendríem més detalls.
L'horabaixa ens defineixen un poc millor el projecte: bàsicament contingut que se'ns aniria passant en format word i que segurament aniria sofrint modificacions damunt la marxa.
Tot just penjar el telèfon ens posarem en marxa. La gent de sistemes creà el repositori subversion pel projecte (no importa la pressa que tenguis, sempre, sempre un control de versions) i inicià la configuració del nou domini.
Una hora després ja teníem el domini intern funcionant i la primera versió del codi dins el subversions. Havíem reaprofitat la funcionalitat que teníem per a la gestió de continguts i ara sols era cosa de crear el disseny, passar-ho a plantilles i posar el contingut. El que ens feia més por era no tenir els DNS replicats per l'hora d'entrega.
El dijous al matí el disseny ja estava llest i es comença a maquetar i pujar continguts. Es crearen algunes plantilles per a fer que les opcions de menú canviessin dinàmicament i s'anava pujant tot al servidor de producció mitjançant un update del subversions. El temps de pujada d'una nova versió era aproximadament de 30 segons, versió que ja pujava testejada gràcies a que amb Django pots anar provant l'aplicació amb el seu servidor integrat (i amb recàrrega automàtica).
Ens sobraren un parell d'hores del temps limit. Total del projecte 35 hores-home. Entregable: aplicació amb subdomini propi, tipus portal de continguts, multi-idioma, amb menús desplegables, i la maquetació a partir de documents word de l'equivalent a una trentena de planes web amb una mescla de text, fotografies i descàrrega d'arxius. Rendiment de l'aplicació: generació d'una plana web en 1,2 segons sense caché.
Si ho haguéssim tingut que fer en Java encara estaríem muntant el CMS o pujant els continguts. Amb les plantilles de Django i la possibilitat d'herència que tenen, poguérem crear el nostre lloc web amb molt poc temps i passar els continguts a HTML de manera molt més ràpida que l'equivalent a crear el disseny en un CMS clàssic de PHP o Java (ja no en parlem de fer el mateix amb Java i sense CMS).
El millor de tot és que encara que no sabíem que se'ns demanaria estàvem raonablement segurs de que si no era res molt complexe es podria fer, ja que el bastiment no ens fermava (com sovint fan els CMS més habituals) sinó tot el contrari.
La meva experiència amb Django? Fantàstica i demostrable. Fins al punt que quan veig el que puc fer en aquest entorn em fa molta peresa tornar cap a Java, els temps d'espera tot i que desenvolupam en local resulten molests, les posades en producció s'eternitzen. I això que gràcies al nostres administradors de sistemes ho tenim tot que va com una seda a l'entorn J2EE i les posades en producció són ràpides, però quan ho compares amb un pocs segons tot resulta lent.
Consider Django com un avantatge competitiu: ens permet fer desenvolpaments molt ràpidament i a més sabem que escalaran bé. Com que no estam lligats a cap bastiment de javascript concret podem incorporar el que necessitem segons el projecte: jQuery, extjs, res... i la separació que es fa en capes de l'aplicació també es pot fer a l'hora de desenvolupar i permet treballar en paral·lel a la gent de sistemes, disseny i programació.
I així doncs, quan voleu que posem Django a la vostra empresa?
Traducciones/Translations by apertium
4 comentaris, 0 trackbacks (URL) , Tags: Python Django
A la pregunta de Servo ....
Escrit per Aaloy a 15 de June , 2008 a les 7:20 p.m.
Al comentari del darrer apunt de Servo es demanava el perquè el Set hauria de ser més ràpid si el primer algorisme és d'ordre N.
El codi dels sets es molt semblant al dels diccionaris, però està una mica més optimitzat, a l'igual que els diccionaris està implementat com una taula hash, però a diferència d'aquests els conjunts sols guarden el parell clau/hash en lloc de la tripleta clau/valor/valor del diccionari.
Com que els sets guarden els parells clau/hash, totes les operacions binàries, com la intersecció s'executen sense cap cridada al mètode _ _hash__ dels elements individuals. Això és molt més ràpid que el codi equivalent que fa servir diccionaris.
També resulta que quan feim un bucle damunt un set Python (CPython) directament recorre la taula hash en lloc de fer ús d'un iterador (que seria un poc més lent).
La pregunta ha servit per fer un poc de recerca, de fet la meva resposta és la traducció d'una resposta molt completa l'he trobada a Python in Science .
Però no ens conformem amb això, fem un "show me the code" a la plana citada anteriorment hi ha un exemple que ens anirà bé per començar. Es tracta de trobar la intersecció de dos conjunts, però ho podem adaptar per fer les cerques al diccionari:
import random import time REPETICIONS = 1000 ## Generam els valors seta = set([random.randint(0,100000) for n in xrange(10000)]) setb = set([random.randint(0,100000) for n in xrange(10000)]) print "Cerques a conjunts" t0 = time.clock() for i in xrange(REPETICIONS): total = seta.intersection(setb) print "Intersections - Time: %s seconds"%(time.clock()-t0) t0 = time.clock() for i in xrange(REPETICIONS): total2 = [] for element in seta: if element in setb: total2.append(element) print "Fent el bucle Time: %s seconds"%(time.clock()-t0) ## I ara el nostre cas print "Cerques amb diccionaris" ## Generam els valors dicta = {} dictb = {} for i in xrange(10000): dicta[random.randint(0,100000)]=i dictb[random.randint(0,100000)]=i t0 = time.clock() for x in xrange(REPETICIONS): total2 = [] for valor in dicta.keys(): if dictb.get(valor): total2.append((valor, dicta[valor])) print "Bucle - Time: %s seconds"%(time.clock()-t0) t0 = time.clock() for x in xrange(REPETICIONS): total2 = [ (repe,dicta[repe]) for repe in set(dicta).intersection(set(dictb))] print "Set intersection - Time: %s seconds"%(time.clock()-t0)
I aquí el resultat
Cerques a conjunts Intersections - Time: 0.94 seconds Fent el bucle Time: 6.11 seconds Cerques amb diccionaris Bucle - Time: 11.63 seconds Set intersection - Time: 6.97 seconds
En el primer cas estam davant un algorisme d'ordre N² davant un algorisme NlogN sin o record malament de la intersecció de conjunts.
El nostre cas és una mica menys clar en el que fa a l'ordre de l'algorisme, però amb el codi es pot veure com el resultat final s'obté és un 60% més ràpid.
Tot i això fixem-nos amb que per a obtenir el resultat en segons he tingut que fer 1.000 iteracions i que hem fet servir un conjunt de 10.000 elements, sols per a que quedi clar de que potser ambdós algorismes són prou ràpids per a la nostra tasca diària. Sols hem de tenir clar que quan cerquem maneres d'optimitzar el nostre codi, mirar si feim aquests tipus d'algorismes moltes vegades
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python
Trobar elements repetits
Escrit per Aaloy a 15 de June , 2008 a les 12:37 p.m.
Tenim el següent problema: "tenim dos diccionaris amb dades i volem trobar els elements d'una diccionari que estan també dins l'altra"
Suposem, per exemple que tenim:
x = {'a':1,'b':2,'r':3}
y = {'a':1,'r':3, 'c':14}
La opció més directe pareix ser la de recorre els elements de la primera llista i veure si hi són a la segona, una cosa com
for valor in x.keys():
if y[valor]:
print valor, y[valor]
a 1 r 3
o bé una altra opció més curta:
for repe in set(x).intersection(set(y)):
print repe, x[repe]
o si m'apurau
[ (repe,x[repe]) for repe in set(x).intersection(set(y))]
[('a', 1), ('r', 3)]
Ara quan algú us demani que és això de que Python ve amb les piles incloses ja teniu un exemple més per a mostrar.
Traducciones/Translations by apertium
4 comentaris, 0 trackbacks (URL) , Tags: Python
Millores al blog
Escrit per Aaloy a 08 de June , 2008 a les 11:30 a.m.
De tant en tant faig feina al blog, no per escriure-hi sinó per afegir-hi noves funcionalitats. Encara hi ha moltes coses que m'agradaria posar-hi i millorar, però a poc a poc esper anar arribant-hi.
A la darrera actualització he fet algunes millores que recomanaven al Google Webmaster Tools com la d'afegir descripcions úniques per apunt. Django a les seves plantilles té el filtre truncatewords_html que m'ha anat fantàstic per això.
Una de les millores que volia fer també era la d'amagar un poc tota la llista de mesos que hi ha. Aquest blog té apunts des del 2004 i la llista començava a ser molt llarga. Ara veureu que sols apareixen els anys (sempre que tingueu el javascript activat clar) i que en pitjar damunt ells es despleguen els mesos. Fer això ha estat entretingut perquè ha implicat jugar amb dos tags més de Django, el for per obtenir si estava a la primera posició del bucle o a la darrera, per tal de poder tancar els divs, i el tag ifchanged que ens permet saber si una variable (en el meu cas l'any) ha canviat o no respecte al seu valor anterior.
Amb aquestes eines ha estat possible muntar l'estructura necessària per a utilitzar un el Animated Collapsible DIV, una petita utilitat per jquery que permet ocultar i mostrar divs a voluntat, agrupant-los per categories si convé.
Ara la plana principal al meu entendre queda un poc més neta i amb prou espai a la columna lateral esquerra per anar afegint més coses.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Informàtica Python Django
Capa de negoci a Django
Escrit per Aaloy a 28 de May , 2008 a les 11:55 p.m.
Del post anterior em quedava el tema de tractar el tema de la capa de negoci en els llenguatges dinàmics. Com en el cas anterior faré servir Django com a exemple i deix al lector la feina d'extrapolar cap el seu llenguatge dinàmic+bastiment preferit.
En Domingo diu que els llenguatges dinàmics mostren molta de la seva potència a la capa de presentació, que és allà on en treuen més profit. Això és veritat però es queda curt. És a dir, quan un usuari demana un canvi, el més habitual és que aquest s'acabi reflexant en la capa de presentació,però això no vol dir que no se canvii la capa de negoci. El fet però és que anar des de la capa de persistència, passant per negoci i mostrar el resultat al navegador, té un cicle de temps més curt en el llenguatge dinàmic, interpretat, que en el compilat, ja que sol ser molt més curt fer els canvis (gearing factor i totes aquestes herbes) i necessitea un temps més curt de desplegament, però no ens enganem, és tot el procés que és curt, si no afecta a capa de presentació el que passarà és que el desenvolupament serà encara més ràpid.
Sovint amb les aplicacions del tipus crea el teu blog en 10 minuts en Django, Rail o qualsevol altra, es dóna una idea equivocada del que se pot fer, donant la imatge de que aquestes aplicacions van molt bé per fer webs que depenen d'un conjunt de taules senzilles i que tenen una lògica de negoci poc complexa.
Bé, supòs que podríem demanar-li a Ricardo, que és un exemple que tenim ben aprop,de com s'ho fa per calcular el karma de Meneame o per saber si una notícia ha de sortir en portada o quan ha de deixar de ser-hi. Tot això es lògica de negoci, està feta en un llenguatge interpretat, el PHP.
En el cas de Django no oblidem que el que tenim per davall és Python i que l'ORM que ens proporciona Django ho podem fer servir o no, substituir-ho per un altre, fer les cridades directament a BD o senzillament, utilitzar-ho com a part del nostre model de negoci i posar-i les regles que ens convenguin.
Segons la nostra aplicació podem anar afegint custom managers que ens permetran definir regles damunt les dades que volem obtenir, mètodes de classe per definir les funcionalitats que vagin damunt tots els elements de la taula, i missatges que ens ajudin a manipular la informació i les seves relacions.
Això ho podem fer directament des de la classe de l'ORM, el model, o bé, recordem que tenim Python a la nostra disposició, crear un nou paquet, crear una classes o un conjunt de classes i utilitzar el model per aplicar les regles de negoci que vulguem quan aquestes s'hagin de convertir en registres de la base de dades o la seva informació hagi de venir de la base de dades. Per cert, i abans que algún ho demani, sí hi ha transaccions!
Això vol dir que podem fer servir els llenguatges dinàmics per a modelar la nostra capa de negoci, doncs sí, ho podem fer. Això vol dir que la nostra aplicació ha d'estar escrita en un llenguatge dinàmic sempre? No, depèn de l'aplicació. Potser per una aplicació concreta amb un requeriments concrets tenir un contenidor EJB amb transaccions distribuïdes serà el que necessitam, el que vull dir és que no podem descartar fer l'aplicació en un llenguatge dinàmic sols perquè ens hem quedat amb la idea de que sols va bé perquè el seu ORM te crea molt fàcilment les taules i els CRUDs.
De fet la part d'administració de Django va molt bé com a eina administrativa, però no és una eina d'usuari final. Com a desenvolupador te va molt bé perquè pots fer cerques ràpidament, començar a omplir les dades del manteniments mestres i anar directament a les butzes de les dades, però no hem de confondre això ni amb l'aplicació final i amb que és tot el que se pot fer amb els llenguatges dinàmics.
I encara hi ha un punt que no hem tractat, el tema de la integració dels llenguatges dinàmics amb els llenguatges compilats (jpython, jruby, groovy, etc). Segons la nostra aplicació i els nostres usuaris, tenir un llenguatge interpretat, fins i tot creat per al domini de la nostra aplicació pot ser una opció molt interessant. Permeteu-me una batalleta: fa un grapat d'anys vaig desenvolupar el programa de gestió d'excursions de l'empresa on feia feina (Delphi + IBObjects + Firebird), una aplicació client servidor clàssica amb un grapat de procediments amagatzemats quan feia falta. La cosa és que hi havia excursions que tenien ofertes que el proveïdor donava i que s'havien de cotitzar, ofertes del tipus: "si es reserva una excursió per dos adults i un nin, el nin tendrà un 25% de descompte damunt la tarifa" o "el tercer adult es gratis i els nins no paguen" etc. Això ho podria haver desenvolupat amb un bon conjunt de camps de la base de dades i tenir previstes les condicions, però la solució hagués estat visualment atractiva però mala de programar i molt propensa a errors. Per contra vaig optar per a modelar-ho con si fos una fórmula de una fulla de càlcul, a la que els meus usuaris estaven acostumant on es podia jugar amb el preu per data, amb sumes, restes, if i tant per cents i parèntesi, un mini intèrpret pensat per a tractar amb fórmules matemàtiques. Les condicions així posades eren flexibles i amb unes possibilitats pràcticament il·limitades respecte al que haurien estat si ho hagués fet amb una "interfície amigable". En aquest cas, integrar un intèrpret a l'aplicació va ser la millor solució.
Com no me cansaré de repetir, no es tracta de dinàmics/interpretats respecte d'estàtics/compilats. Es tracta de perdre la por i els perjudicis i poder triar en cada cas aquella tecnologia que millor s'adapti al problema a resoldre de manera que aquest es pugui resoldre amb el menor cost actual i futur per al nostre client, en alguns casos aquest llenguatge serà C, C++, C#, Java o el que sigui, però en altres, en molts altres un llenguatge dinàmic serà la millor opció per als nostres clients.
Traducciones/Translations by apertium
5 comentaris, 0 trackbacks (URL) , Tags: Python Django Gestió de projectes
D'errors i línies de codi
Escrit per Aaloy a 26 de May , 2008 a les 9:30 p.m.
En Domingo al seu blog fa una referència al meu apunt damunt llenguatges dinàmics i un bon grapat de bones reflexions.
Això de no creure's el que dic és una postura molt sana, sobretot perquè en la redacció d'un apunt me puc deixar detall i dades que són interessants. Una postura crítica ajuda a reflexionar i a completar les frases que d'altra banda s'haurien deixat com a dogmes de fe. Jo sóc del mateix tarannà, hi ha coses que me crec i coses que a poc que vegi indicis de contradiccions, doncs cerc més informació o deman explicacions. Això, he de dir també, m'ha causat força problemes en el món empresarial, on sovint el "no pensis" és una qualitat que ajuda a progressar.
Bé, però no me'n vull anar per les bardisses, o sí, ja que hi sóm, aprofitaré per dir perquè no faig servir el Twitter: no hi ha espai abastament :)
Afirmació: El nombre de línies de codi que escriu un programador al dia és una constant. Això és un efecte estadístic. Fa temps es parlava de que un programador escriu cinc línies de codi sense errors al dia. Està clar que és una dada estadística i fins i tot controvertida, ja que que és molt complexa definir què és i que no és una línia de codi i de que les línies de codi no s'han de fer servir per mesurar el rendiment. Tot i això podem trobar referències capítol 5 de Software estimation de McConnell on a la Taula 5.1 torbam la relació entre les línies d'un projecte i les línies de codi per programador i any. Això no vol dir que tots els programadors escriguin les mateixes línies de codi (de fet la productivitat entre programador pot arribar a un factor 10 -Peopleware-, però sí que en mitja i per a una organització i projecte, el nombre de línies de codi que s'escriu en promig és constant. A Sofware Mesurement and Estimation diu "Studies have shown that a proficient programmer can programm aproximately the same number of debugged lines of code per day regarless of the language". D'aquí que gent com QSM o David Consulting Group facin comparatives entre llenguatges per a comparar l'expressivitat de cada llenguatge. Per exemple C té un gearing factor de 128 i Java de 53. Això vol dir que una funció que en C necessita 128 línies de codi en Java en necessitarà en promig 53. Si un programador experimentat escriu, essent optimistes 10 línies de codi depurat al dia, llavors necessitarà 13 dies en C i 6 en Java (nombres redons).
D'aquí llavors que els llenguatges dinàmics, al necessitar menys línies de codi per fer el mateix poden completar els projectes en un temps més curt. Com que el temps significa doblers, implica que els projectes surten més barats.
Afirmació: el número de errores directamente proporcional al número de líneas que se escriben Aquí també entram en temes estadístics. De fet es parla de nombre d'errors d'un programa per mils de línies de codi. De la mateixa manera que en el cas de les línies de codi que escriu un programador, hi ha moltes diferències, però Casper Jones a "Program Quality and programmer Poductiviy (1997)" va recopilar algunes dades, que també cita en McConnell. També Reifer en va fer estudis, per exemple per la part Web estudià 65 projectes, i trobà que el ratio és de 6 errors per KESLOC (KESLOC Kilo (Thousand) Equivalent Source Lines of Code). Aquest nombre depèn força del tipus del projecte i de l'organització, però és estadísticament significatiu. Per tant, si donam com a bo el que els llenguatges dinàmics necessiten menys línies de codi per expressar el mateix que els llenguatges compilats tradicionals (Java, C, C+, ...) tendrem que el nombre d'errors en valor absolut també serà menor.
He trobat també una comparativa entre el nombre d'erros per Java i C++ a un paper de Geoffrey Phipps anomenat Comparing Observed Bug and Productiviy Rates for Java and C++, me l'he d'acabar de llegir, però conclou que amb un 95% de confiança C++ té 9,7 vegades més defectes per KLOC que Java i que a més els defectes en Java són més fàcils de corregir. D'aquí a fer una extrapolació cap a la banda dels llenguatges dinàmics hi ha sols un pas, sols falta que algú s'animi a fer l'estudi.
En Domingo també demana l'opinió damunt els llenguatges dinàmics per la capa de negoci, però això crec que dóna per un apunt per ell sol, així que ho deixaré per la propera vegada, però promet, amenaç, amb tractar-ho.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Informàtica Python Django Gestió de projectes
Llenguatges dinàmics
Escrit per Aaloy a 25 de May , 2008 a les 11:18 a.m.
Al blog de Ricardo he esta llegint l'apunt anomenat "Lenguajes dinámicos, programadores y FUD" així com els seus comentaris. Tot i que hi he deixat allà un comentari amb la meva opinió, crec que com a programador en llenguatges dinàmics i tradicionals he de dir la meva.
El primer de tot que voldria fer és evitar el FUD damunt els llenguatges dinàmics, per una raó molt senzilla: la realitat és molt cruel i estam cansats de veure i de llegir damunt projectes web realitzats en Python, Ruby o PHP que estan triomfant i que no desapareixen o exploten per mor de no tenir un llenguatge compilat al darrera. Per tant, la primera cosa que hem de tenir clara és que la teoria pot estar molt bé, però la realitat ens està dient dia a dia que és possible escriure i mantenir programes en llenguatges dinàmics. A un li poden agradar més o menys aquests tipus de llenguatges, però el que no es pot fer és negar la realitat.
També m'agradaria focalitzar l'àmbit de discussió: estam parlant de programes web. Per programes d'escriptori no tenc dades abastament, potser perquè els llenguatges dinàmics brillen en el desenvolupament web més que en la part d'escriptori, llevat de que considerem el Visual Basic com a llenguatge dinàmic, clar.
La cosa està en que amb les màquines actuals els llenguatges dinàmics son ja prou ràpids com per ser competitius amb els llenguates compilats. Això no vol dir que siguin més ràpids, sinó que són prou ràpids per fer la feina i que la diferència de velocitat que hi hagi no sigui rellevant. Que PHP ens serveixi una plana en 1 segon i en Java la serveixi en 0,98 segons, doncs no és rellevant ja que per l'usuari de l'aplicació no significarà cap diferència en l'espera.
Això vol dir que ens hem de passar ja a programar en un llenguatge dinàmic i deixar els compilats? No. Vol dir que és necessari que a més d'un llenguatge tradicional convé que tinguem al caixò de les eines un llenguatge dinàmic. D'aquesta manera quan ens demanin una aplicació podrem sospesar els pros i els contres i fer-la en el llenguatge que s'adapti millor al projecte. Fins i tot si el nostre projecte es farà en un llenguatge tradicional, tenir un llenguatge dinàmic se pot integrar al projecte en forma de rutines de generació de codi, scripts de testeig, etc.
Dit això, i considerant l'àmbit de les aplicacions web, anem a veure avantatges i inconvenients d'elegir un llenguatge dinàmic per al nostre projecte, com que el que més conec és el Python, em permetreu la llibertat de donar els exemples i les referències en aquest llenguatge, in en Java en el cas de llenguatge compilat, en el ben entès que segur que hi ha el mateix tipus de solucions en Ruby, PHP o el vostre llenguatge dinàmic preferit i en C, C++ o .Net, etc.
Cicle de desenvolupament Agafem una aplicació web típica Java desplegada a un servidor Tomcat i la mateixa aplicació feta en Python. El cicle al primer cas és: escriure codi, compilar, corregir els errors de sintaxi, desplegar-ho al servidor, provar i iniciar novament tot el cicle, bé per escriure nou codi o bé per corregir els errors. A l'aplicació Python+Django tendríem: escriure codi, provar i tornar a escriure el nou codi. L'augment de productivitat la tenim no per el fet de no tenir que corregir errors, sinó pel fet de no tenir temps d'espera en el desplegament i per haver d'escriure menys línies de codi.
Errors de sintaxi. Aquí algun haurà pensat, "s'ha deixat els errors de sintaxi", efectivament, ho he fet perquè vull dedicar-lis el seu propi apartat. El compilador caça els errors de sintaxi i ens n'informa, però això vol dir que hem d'executar el compilador, és veritat que això els IDEs com Eclipse ho fan automàticament, però tot i això s'ha de fer. Realment podem fer el mateix amb eines com Pylint o Pychecker i a més el primer a més és capaç de treure tot un conjunt d'estadístiques damunt la qualitat del codi, talment com ho fan eines Java com PMD. El pylint per exemple és el que fa servir PyDev per a indicar els errors de sintaxi i donar avisos damunt el codi. Està clar que aquests errors potser no seran tan acurats como els dels compiladors, però són prou bons com per fer la feina, amb l'avantatge, però que ho podem llançar quan nosaltres vulguem i que no s'ha de passar necessàriament pel compilador per a executar el programa.
Per una altra banda, que el compilador o pylint ens caci els errors de sintaxi ens pot donar una falsa sensació de seguretat, el errors de sintaxis poden fer petar l'aplicació, és veritat, però els errors més greus solen ser els errors en la lògica de negoci de l'aplicació. Quan aquests se detecten el que s'ha de fer és corregir-los el més aviat possible, i en aplicacions web entram en
La fase de desplegament El temps que necessitam per posar una aplicació en producció seria anecdòtic si les aplicacions no tinguessin errors. Necessitar 30 minuts o 10 minuts per una aplicació que es posi en producció i que estigui mesos o anys sense modificar-se no és significatiu. Però, si l'aplicació sofrirà canvis o els errors que es detectin s'han de resoldre el més aviat possible, una diferència de 30 minuts en el desplegament pot marcar la diferència. En el cas d'un error en la lògica de l'aplicació que afecti a un .jar, significa en el millor dels casos compilar l'aplicació o el jar corresponent, substitur-ho i reiniciar el servidor d'aplicacions o l'aplicació, cosa que pot dur entre uns 30 segons y un bon grapat de minuts, depèn del que hi hagi desplegat. El el cas d'un llenguatge dinàmic sovint basta actualitzar els arixus afectats (svn update per exemple) i fer un reload del servidor Apache que tenguem. Cosa d'un parell de segons tot plegat. Està clar que podem minimitzar el primer cas amb servidors redundants i configuracions d'alta disponibilitat, però a un cost major de complexitat.
L'orientació a la tasca Les aplicacions web tracten fonamentalment amb text i produeixen text. Agafam dades de formularis, les tractam, obtenim dades de les bases de dades i les manipulam per a presentar-les a l'usuari en una sortida HTML, etc. Tractar cadenes és part fonamental de les aplicacions, i això és una cosa que els llenguatges compilats fan en general força malament des del punt de vista del nombre de línies de codi que s'han de picar. Els llenguatges dinàmics són força bons tractant informació textual. Posaré un exemple que ens pot servir per il·lustrar aquest fet: les plantilles. En Java tenim tres llenguatges de plantilles principalment: JSP-EL (ja ho sé està agafat pels pels però acceptau-me'l), Freemaker i el venerable Velocity i en general són força infumables. Comparem-ho amb el que hi ha per Python i veurem la diferència (Django, Web String, Cheetath, Mako, Jinja, ...). No crec que sigui anecdòtic, la diferència és que és força senzill manipular text en Python i per tant és força senzill crear-te el teu propi llenguatge de plantilles.
Productivitat El nombre de línies de codi que escriu un programador al dia és una constant. Això vol dir que si volem tenir més productivitat s'ha d'anar cap a llenguatges que ens permetin escriure més funcionalitat en menys codi. Donat el boom que viuen actualment els llenguatges dinàmics encara no hi ha molta literatura al respecte in encara no hi ha ni Ruby, ni PHP ni Python al QSM, però sí que hi ha forces comparatives, una de les més interessants és la d'Stephen Ferg que senyala que programar en Python és de 5 a 10 vegades més productiu que fer-ho en Java.
Diversió i motivació Els llenguatges dinàmics són sexy. Permeten al programador un alt grau de realimentació. Pot provar les seves idees molt ràpidament i això el motiva molt més que tenir que esperar a que el compilador acabi per poder fer les proves.
Pel demés, els llenguatges dinàmics també necessiten unit tests (sols que es poden escriure més ràpidament i amb menys línies), una gestió acurada dels projectes, planificació del que volem fer i refactorització del codi.
La conclusió de tot això és que deixem de banda FUDs que no duen a res i a l'hora d'avaluar un projecte considerem també si és apte per a ser fet en un llenguatge dinàmic, si ho és endavant, el nostre cul no perilla per dita elecció, ja que tant Python, com Ruby com PHP seran prou capaços de fer la feina.
Traducciones/Translations by apertium
3 comentaris, 0 trackbacks (URL) , Tags: Informàtica Python Django
vim ide per python
Escrit per Aaloy a 17 de May , 2008 a les 9:22 a.m.
Aquesta setmana i gràcies a l'entrada del blog de sontek he retornat al vi com a editor principal per a la programació en Python.
Periòdicament estic canviant entre vim, kate o Eclipse amb PyDev, segons la màquina en que faig feina i el que estic fent, però pas gran part del temps fent feina amb la consola i trobar la configuració que permet tenir el millor de els entorns gràfics a vim m'ha sorprès gratament.
Amb la configuració i el conjunt de plugins que ha seleccionat sontek tenim un editor que permet tabs, autocompletat, plantilles, integració amb subversion i tota la potència d'edició de vim. El tema del depurador integrat està un poc més verd, però tampoc l'he trobat massa a faltar.
A un dels comentaris hi havia la recomanació per a la instal·lació a més de NERDTree un navegador de fitxers integrat al vim que facilita molt la vida, i també ho vaig posar. També he adaptat les plantilles que venen per Django per a que agafi la sintaxi del trunk i he afegit algun retoc més com que posi la codificació als fitxers i coses així, les plantilles són tan bones de modificar que me pareix que puc acabar amb un bon repositori de codi :)
Tot i que no poseu la configuració crec que és interessant fer-hi una ullada a com ha organitzat Sontek (John M. Anderson) el seu fitxer de configuració per veure un exemple del que es pot fer amb vim i de com es pot incloure codi Python dins l'arxiu de configuració. Una de les maneres d'aprendre a programar és llegir codi d'altres (bon codi si és possible) i en l'arxiu de configuració de vim podem dir el mateix: llegint configuracions d'altra gent podem arribar a personalitzar l'editor fins a límits insospitats.
Traducciones/Translations by apertium
4 comentaris, 0 trackbacks (URL) , Tags: Python Django
Primeres modificacions al blog nou
Escrit per Aaloy a 15 de April , 2008 a les 9:11 p.m.
Avui he fet les primeres modificacions al Blog. Ja us deia que això de posar en producció les coses et força a trobar i corregir els errors més ràpid.
M'he trobat que els RSS no funcionaven. La idea era mantenir la compatibilitat amb els RSS de Wordpress, de tal manera que els vells subscriptors no notassin el canvi, però me vaig deixar una s i no anaven. El canvi ha esta molt senzill, però ha sigut cosa d'esperar a arribar a casa per fer les modificacions.
De pas he aprofitat per arreglar quatre etiquetes que no estaven ben posades i posar una validació als comentaris de manera que "peti" en posar un comentari buid. La part de comentaris és potser el que menys m'agrada, ja que encara fa servir les llibreries de oldforms de Django i jo ja estic molt acostumat a les noves. El canvi de oldforms a newforms serà de les primeres coses que vull fer. El que em frena un poc és la part de control de l'spam, però miraré si puc fer servir algun component per a connectar amb l'Akismet i fer-ne el backoffice per a controlar-ho.
De les coses que més m'agraden del nou programa és la possibilitat de fer servir el Markdown per a escriure els posts. Al Wordpress segurament se deu poder fer alguna cosa per l'estil, però no m'hi he volgut barallar mai. Vaig posar també javascript per a colorejar codi Python, així que ara veureu que els articles que tenguin codi quedaran un poc millor presentats.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python Django
Powered by Django
Escrit per Aaloy a 14 de April , 2008 a les 9:24 p.m.
Un dels propòsits del 2008 pareix que ja s'ha complert. Gràcies a Bernat avui hem canviat el blog vei en wordpress que quedarà a blog.trespams.com, més que res per si alguna cosa anàs malament mentre es fa el canvi.
El nou blog està en fase beta, però seguint els principis del la programació àgil, he preferit posar-ho en producció i anar polint els detalls que queden. Com podeu veure pel titol el blog és Django powered. Corre damunt un servidor dedicat que tenim per APSL dins un entorn chroot que en Bernat ha montat.
El codi font del blog està disponible al repositori de google code, com a una branca amb suport unicode del blogmaker, així que tothom és benvingut a col·laborar-hi i a posar-hi tickets pels errors que segurament hi trobareu.
Al codi font també hi ha l'importador de Wordpress cap al blog, de manera que veureu que els articles de l'antic lloc, comentaris i trackback estan inclosos en el nou. La importació no ha estat massa complexa i s'ha fet a partir de l'exportación en format RSS que fa el Wordpress. Tot i això hi ha petites millores a fer, com les de tractar millor els paràgrafs. Alguns articles encara no han passat per la modificació i les lletres es veuen molt atapides, fruit de la combinació de l'importado i de la fulla d'estils que he fet servir per a contruir el lloc, el multiflex.
Encara queden cosetes a polir, veig que m'he deixat el peu del "powered by django" per exemple, la part d'agraïments, etc. etc. que aniré posant durant els propers dies i setmanes. El d'avui és una beta, gairebé alfa, però com us dic, crec que l'important és perdre la por i posar-ho en producció i anar-ho millorant dia a dia.
Traducciones/Translations by apertium
6 comentaris, 0 trackbacks (URL) , Tags: Python Django
Ja tenim el compte d’Appengine
Escrit per Aaloy a 11 de April , 2008 a les 11:37 p.m.
Doncs això, fa poques hores he rebut el missatge que diu que ja puc fer coses amb l'Appengine de Google, en morenosan en va dir ahir que havia rebut també el seu, així que pareix que estan obrint el grifó bastant de pressa.
Ara es cosa d'anar pensant què es pot fer. De totes maneres no es tant l'aplicació en sí, com poder provar l'entorn i començar a veure les seves possibilitats, com s'hi fa feina, quines diferències hi ha entre poder fer l'ORM de Google i el de Django, veure les limitacions que ens imposa...
Temps al temps!
Traducciones/Translations by apertium
1 comentari, 0 trackbacks (URL) , Tags: Python Django
Bons temps per Python
Escrit per Aaloy a 09 de April , 2008 a les 12:03 a.m.
La blogosfera en va plena Google ha llançat el seu appengine , un servei que permet hostejar aplicacions de fins a 500 Mb d'espai i 5 milions de visites mensuals que Google ha llançat i que té com a llenguatge vehicular el Python.
Per a accedir-hi un s'ha d'apuntar a la llista d'espera, ja que pareix que els comptes en fase beta s'han esgotat, i tot i les limitacions del sistema en el que fa referència als accessos als sistemes de fitxers, limitacions de la part de base de dades, que no es puguin llançar subprocessos i coses per l'estil, obre la possibilitat a tot un ventall d'aplicacions web.
On la notícia ha impactat més és a la comunitat Python: un llançament espectacular de Google, amb Guido pel mig, am Python com a protagonista i amb Django com a estrella convidada, ja que Django, encara que la versió "estable", ve de sèrie en el sistema.
Si encara no ho heu fet és un bon moment per aprendre Python i Django (ueps, tal volta seria un bon moment per publicitar-ne cursos :-P ) ja que un dels emperòs més grans que hi havia és que no se disposava d'un servidor a preus assequibles on poder fer anar les aplicacions. Ara amb el llançament de Google, les possibilitats de fer desenvolupaments amb Python i Django es multipliquen, limitats a les possibilitats de l'entorn que proporciona Google, sí, però permetran en breu començar a fer aplicacions web i hostetjar-les a un preu inmillorable.
Amb això esper a més que els hostingaires de sempre es posin les piles i donin a preus raonables allotjament per Django, proporcionant a més el servei que ara Google no ofereix: el de tenir una base de dades relacional pròpia al darrera.
I és que un dels grans problemes de l'oferta de Google és que no ets ben bé l'amo de la teva base de dades i algunes coses que permet fer l'ORM de Django molt fàcilment a l'ORM substitutiu de Google no es poden fer.
És clar que no totes les aplicacions necessiten d'una base de dades relacional al darrera, així que l'appengine de Google és per una part un bon banc de proves per veure com va això de la programació web amb Python i Django i per una altra una manera ràpida i econòmica de posar en producció projectes web que d'altra manera tendrien un cost prohibitiu pel programador mig.
Traducciones/Translations by apertium
2 comentaris, 3 trackbacks (URL) , Tags: Informàtica Python Django
Propietats a Python
Escrit per Aaloy a 21 de March , 2008 a les 1:41 p.m.
En Corey Goldberg al seu blog a un recull interessant d'enllaços de lectura obligada per aquella gent que està fent la transició de Java o C# cap a Python.
Un dels més interessant és l'article de Phillip J. Eby anomenat Python is not Java on recull les diferències fonamentals que hi ha entre programar en Java o programar en Python. Una de les afirmacions més xocants és potser aquesta: Getters and setters are evil. Evil, evil, I say! Python objects are not Java beans. Do not write getters and setters, és a dir "Els getter i setters són el dimoni. El Dimoni, dic. Els objects de Python no són Java beans. No escriguis getters i setters."
La frase pot semblar molt bèstia, i de fet ho és, ja que és una afirmació que s'ha de matitzar molt, com de fet ho fa en Ryan Tomayko al l'apunt Getters/Setters/Fuxors on s'explica molt bé quan fer servir aquest tipus de construccions, però en definitiva el que ens hem de quedar és amb la idea de que normalment Python no necessita mètodes accessors i que l'ús normal d'aquest és el de marcar un atribut com de sols lectura.
Com sempre hi ha "la manera de Python" de fer les coses, i sol ser la manera més senzilla de fer-les.
Traducciones/Translations by apertium
1 comentari, 0 trackbacks (URL) , Tags: Informàtica Python
Integració de Hudson i Trac
Escrit per Aaloy a 15 de March , 2008 a les 11:52 a.m.
A un altre post ja vaig parlar de Hudson, un sistema d'integració contínua, relativament nou però que permet fer el que un necessita d'aquestes característiques de manera fàcil i amb una interfície molt cuidada.
Hudson es pot integrar amb Trac, de manera que al Timeline del projecte trac poguem veure com han anat les integracions sense tenir que anar al Hudson. D'aquesta manera la gent que fa el seguiment del projecte pot veure a més dels commits al subversions, modificacions al wiki i tickets, com han anat les integracions i quan s'han fet.
La integració dels dos aplicatius és força senzilla:
- Instal·lam el python-feedparser si no ho tenim ja al nostre servidor.
- Anam a http://trac-hacks.org/wiki/HudsonTracPlugin i descarregam el plugin.
- Descomprimim el plugin i amb permisos d'administrador executam python setup.py install això ens crearà el paquet egg i configurarà el plugin a nivell global dins el trac.
- Editam l'arxiu trac.ini del nostre projecte trac que volguem enllaçar amb Hudson i modificam la llista de components, en el meu cas la cosa queda com
[components] iniadmin.iniadmin.iniadminplugin = enabled webadmin.* = enabled HudsonTrac.* = enabled
- Cream també una entra a anomenada hudson allà on posarem tant la url del rss del nombre projecte hudson que volguem controlar com el de la vista del projecte, de tal manera que s'hi crei un enllaç dins Trac
[hudson] display_subprojects = false feed_url = http://servidorhudson/hudson/view/Java/rssAll main_page = http://servidorhudson/hudson/view/Java/
- Canvia el servidorhudson pel vostre servidor. Aquí el que he fet és enllaçar directament contra la vista de projectes anomenada Java que he creat. Podria enllaçar a un projecte concret o a una vista relacionada amb el projecte que es gestiona amb el Trac.
Si s'han seguit aquestes passes i una vegada refrescada la plana del Trac, ens apareixerà una nova secció anomenada Hudson a la part de navegació del Trac que enllaça a la url que hem posat a main_page i al timeline apareixerà una opció que ens permetrà visualitzar les integracions, en forma de control check.
Pels que feu servir Trac de manera habitual, és interessant instal·lar-se també el plugin IniAdminPlugin, que ens crea un menú de configuració per web del trac.ini del nostre projecte.
És interessant a tot això adonar-se de que gràcies als formats oberts, en aquest cas al RSS que publica Hudson i que pot consumir Trac, dues aplicacions fetes en tecnologies totalment diferents es poden integrar.
Al Hudson passa una cosa semblant, està pensat per tractar amb format oberts, típicament sortides XML en format UnitTest, la qual cosa permet afegir-hi projectetes de Python, Java o SoapUI.
Traducciones/Translations by apertium
2 comentaris, 0 trackbacks (URL) , Tags: Informàtica Python Java
Winpdb
Escrit per Aaloy a 27 de January , 2008 a les 11:15 a.m.
Winpdb és un depurador en mode consola i gràfic per aplicacions Python.. Fa un parell de setmanes que han alliberat una nova versió. En la seva part gràfica, el programa presenta una interfície clara i permet la depuració remota de les aplicacions.
Es pot utilitzar per depurar scripts de Python molt fàcilment sols executant el programa passant-hi com a paràmetre l'script a depurar, tal com se fa amb el depurador estàndard de Python.
La vertadera potència, però està en la facilitat en que es poden depurar aplicacions remotes o aplicacions com les que es poden fer en Django per exemple. En a quest cas afegint aquesa línia al que vulguem depurar
import rpdb2
rpdb2.start_embedded_debugger_interactive_password('clau de seguretat')
ens permetrà connectar-hi el depurador.
Winpdb fa temps que roda, però és la primera vegada que puc fer anar la depuració remota sense problemes. Una eina més a afegir a la capça de programació.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python
Què torbes a corregir un error de producció?
Escrit per Aaloy a 18 de November , 2007 a les 4:34 p.m.
Trobar un error al teu codi és un emprenyo. Poder començar la depuració en 30 segons, trobar l'error 2 minuts, pujar-ho al subversion i actualitzar la versió de producció de manera que als 5 minuts d'haver detectat l'error estigui corregit no té preu.
Això és el gran avantatge dels llenguatges d'script, que el temps que passa des de que trobes un error a poder-ho corregir és molt curt (llevat d'excepcions amb errors difícils de trobar i depurar, clar). Curt perquè normalment posar en marxa l'entorn de desenvolupament no duu més que uns pocs segons i ja pots començar a depurar.
Si tot està ben organitzat el codi estarà a un repositori subvesion i l'entorn de producció no serà sinó un client de subversion, de manera que fer una actualització una vegada trobat un error que no afecti a la base de dades, és bàsicament
- svn ci
- ssh al servidor
- svn update
I en alguns casos recarregar l'Apache. Encara desenvolupament i sistemes siguin equips separats, davant un error crític el temps de resposta pot ser tan curt com 5 minuts.
L'experiència amb Java és que ja directament és necessiten els 5 minuts sols per posar en marxa l'entorn, 5 o 10 minuts més per depurar i si hi ha sort i sols era un error de jsp 2 mintus més actualizar i forçar la compilació del jsp per a que el proper usuari no vegi en enlentiment en la pàgina. Normalment més del doble per a corregir el mateix tipus d'error.
Si la correcció de l'error implica canviar codi que no sigui jsp o html les diferències són encara més grans i sovint pot implicar tenir que reiniciar el servidor, la qual cosa ens obligarà a tenir sempre dos servidors balancejats si no volem tenir als usuaris aturats durant 5 minuts. L'Apache es recarrega en segons, i tot i que sempre és bo tenir-ho tot duplicat i balancejat, la necessitat no es tan forta com en el cas anterior.
Personalment m'agrada molt Java i les llibreries que s'han desenvolupat en aquest llenguatge, però si el nostre negoci depèn del ràpid que puguem actualitzar la nostra aplicació web hi ha entorns i llenguatges amb més avantatges que Java o .Net.
Traducciones/Translations by apertium
4 comentaris, 0 trackbacks (URL) , Tags: Python Java Gestió de projectes
Ordre a la llista!
Escrit per Aaloy a 23 de September , 2007 a les 7:18 p.m.
Una de les accions més repetitives que sovint feim quan passam cap a la capa de presentació és la d'ordenar els elements que volem que es presentin. Potser algú dirà que els elements ja poden venir ordenats de la consulta a la base de dades, però què passa si en lloc d'atacar a una base de dades directament obtenim el que s'ha de mostrar d'un servei web? o ja hem fet un tractament de les dades i ara les volem ordenar per un altra camp. Poder fer ordenacions de manera senzilla i ràpida ens soluciona molts maldecaps.
Anem a veure com Python ens permet fer ordenacions de llistes de pràcticament qualsevol cosa. Python fa servir el mètode sort per a ordenar una llista. L'exemple més senzill seria l'ordenació d'una llista d'enters
$ llista = [2,4,5,6,7,6,7] $ llista.sort() $ llista [2, 4, 5, 6, 6, 7, 7]
Sí, és tan senzill com pareix, i fins i tot podem fer
$ llista.reverse() $ llista [7, 7, 6, 6, 5, 4, 2]
Però clar, una llista a Python pot contenir qualsevol cosa, no sols sencers, anem a veure què passa si passam una llista de parells (tuples)
$ llista = [(1,5),(1,2),(2,2),(3,5),(4,8),(1,9)] $ llista.sort() $ llista [(1, 2), (1, 5), (1, 9), (2, 2), (3, 5), (4, 8)]
Suposem però que jo el que vull és que s'ordeni pel segon element de la tupla, aquí si un prové d'altres llenguatges de programació ja se pot esperar tenir que escriure un bon munt de codi, però no en Python, l'ordenació es fa per una clau i podem definir quina és aquesta clau passant-li al mètode sort una funció construida de manera que prengui un sol element i ens retorni la clau a comparar.
Per fer el que volem farem servir el mòdul operator, i dins aquest la funció itemgetter, aquesta funció ens retorna una altra funció que aplicada damunt una llista o tupla ens donarà l'element especificat que haguem definit, així per exemple
$ segon=itemgetter(1) $ segon(llista) (2, 2) $ llista [(1, 2), (2, 2), (1, 5), (3, 5), (4, 8), (1, 9)] $ segon(llista) (2, 2) $ segon((1,5)) 5
Farem servir aquesta funció per a obtenir la clau per la qual volem ordenar la nostra llista, així
$ llista.sort(key=segon) $ llista [(1, 2), (2, 2), (1, 5), (3, 5), (4, 8), (1, 9)]
Pensem en les implicacions que té això quan volem omplir un select d'html, encara que la llista ens hagi arribada ordenada per codi, podem fàcilment canviar l'ordenació al texte sols amb aquesta instrucció. Un altra paràmetre que ens serà de molta utilitat a l'hora de fer ordenacions és el cmp, aquest ens permet passar una funció que donats dos arguments haurà de retornar un nombre positiu per indicar que el primer és major que el segon, zero per indicar que els elements són igual o negatiu per indicar que el segon és major que el primer.
Per exemple, suposem que el que volem fer és ordenar la nostra llista segons el que sumen els seus components.
$ t=llista[:] #Farem primer una còpia de la llista original
$ def ordena(x,y):
p1 = x[0]+x[1]
p2 = y[0]+y[1]
return p1-p2
$ t.sort(cmp=ordena)
$ t
[(1, 2), (2, 2), (1, 5), (3, 5), (1, 9), (4, 8)]
$ llista
[(1, 2), (2, 2), (1, 5), (3, 5), (4, 8), (1, 9)]
O també poden fer un codi més florit i escriure
$ t = llista[:] $ t [(1, 2), (2, 2), (1, 5), (3, 5), (4, 8), (1, 9)] $ t.sort(lambda x,y: x[0]+x[1]-y[0]-y[1]) $ t [(1, 2), (2, 2), (1, 5), (3, 5), (1, 9), (4, 8)]
Si algú ha tingut la paciència d'arribar fins aquí, un momentet, que ara ve el més interessant. Què passa quan en lloc de llistes de nombres tenim llistes d'objectes? Doncs res, podem fer servir el paràmetre cmp o el paràmetre key segons ens vagi millor per fer l'ordenació. Anem a veure tres maneres de fer el mateix. Primer definirem la nostra llista d'objectes
class Persona:
def __init__(self, nom, edat):
self.nom = nom
self.edat = edat
def __cmp__(self, altri):
return cmp(self.edat,altri.edat)
Aquí el que he defint és una funció cmp dins la classe, que és la que faríem servir per defecte a l'hora d'ordenar una llista d'objectes d'aquest tipus, així:
$ agenda = [Persona('Benjamí', 31), Persona('Pau', 22),
Persona('Juan',34), Persona('Ricardo',38),
Persona('Guillem',28),
Persona('Bernat',58)]
$ agenda.sort()
$ for amic in agenda:
$ print "%25s \t %i" % (amic.nom, amic.edat)
Pau 22
Guillem 28
Benjamí 31
Juan 34
Ricardo 38
Bernat 58
Ara suposem però que volem ordenar la llista per nom. Una opció seria refer el mètode cmp, però tenim altres opcions. La primera és encriure una nova funció de comparació:
$ def compara_nom(amic1, amic2): $ return cmp(amic1.nom,amic2.nom) $ agenda.sort(compara_nom) $ for amic in agenda: $ print "%25s \t %i" % (amic.nom, amic.edat)
Benjamí 31
Bernat 58
Guillem 28
Juan 34
Pau 22
Ricardo 38
O bé, si ens agrada més l'opció lambda
$ agenda.sort(lambda amic1, amic2: cmp(amic1.nom,amic2.nom))
Però encara tenim una altra maner, deixant que Python faci la feina per nosaltres, hem d'indicar la clau d'ordenació i fer que les eines de comparació del llenguatge facin la seva via. El problema però està en com dir-li quina clau fer servir, això s'aconsegueix amb attrgetter de la llibreria operator.
$ agenda.sort(key=attrgetter('nom'))
$ for amic in agenda:
$ print "%25s \t %i" % (amic.nom, amic.edat)
Fixau-vos el senzill que seria poder fer una ordenació per qualsevol camp de la classe.
Referències:
Traducciones/Translations by apertium
1 comentari, 0 trackbacks (URL) , Tags: Python
Creant objectes a la manera de Python.
Escrit per Aaloy a 09 de September , 2007 a les 10:33 p.m.
- El patró MVC (Model view controller) de sobres conegut per la gent que es dedica al desenvolupament web fonamentalment.
- El patró MVP (Model view presenter) , que intenta fer que la part d'interacció sigui més testejable y que Flower ha considerat que s'havia de xapar en dos.
- El patró Presentació Model, que independitza la capa de presentació de la vista, en un intent de separar el que és la part de comportament i estat de la vista en un model que és part de la presentació però que no es específic d'una implementació d'interfície concreta.
class Agenda:
... def __init__(self, nom, llinatge, telefon, amic=True):
... self.nom = nom
... self.llinatge = llinatge
... self.telefon = telefon
... self.amic = amic
...
La manera habitual de crear un objecte de tipus Agenda seria per exemple
amic = Agenda('toni','aloy','971xxxxxxx')
Suposem ara que tenim la informació dins una llista o una tupla, bastant habitual si per exemple hem importat les dades d'un arxiu de text o des de una base de dades, aleshores podem tenir la informació com
un_amic =('Pau','Rul·lan','971xxxxxxx')
La creació de l'objecte és molt ràpida d'escriure
amic2 = Agenda(*un_amic)
amic2.nom
'Pau'
És a dir, s'han substituït els paràmetres de construcció de l'objecte pels valors de la llista. Aquesta substitució és posicional, és a dir, el primer valor correspon al primer paràmetre, el segon al segon, etc. La sintaxi és conseqüent amb la manera d'anomenar llistes de paràmetres en la construcció de funcions, per exemple:
def prova (x, *y):
... print x
... for item in y:
... print item
...
prova(2,3,4,5,6,7)
2
3
4
5
6
7
prova (2,7,10)
2
7
10
Però clar, si això funciona d'aquesta manera i estam parlant de Python i haurà una manera obvia de fer el mateix si en lloc d'una llista tenim un diccionari, és a dir, ara tenim:
un_amic ={'nom':'Benjamí','llinatge':'Villoslada','telefon':'971xxxxxxx'}
Les claus del diccionari coincideixen amb els noms dels paràmetres, i hauríem de poder fer
amic3 = Agenda(**un_amic)
Això és Python, i per tant
amic3.nom
'Benjam\xc3\xad'
Traducciones/Translations by apertium
3 comentaris, 0 trackbacks (URL) , Tags: Python
Trac i clearsilver
Escrit per Aaloy a 20 de August , 2007 a les 9:07 p.m.
El clearsilver és una llibreria de plantilles que abans feia servir el Trac i que s'està substituint a favor de Genshi, una altra llibreria que segons la gent de Trac els causa molt menys problemes.
La cosa està, però, en que no es lleven les dependències fins a la versió 0.11 no s'eliminen les dependències de clearsilver i fins i tot en aquesta versió es mantindran les estructures necessàries per a que els plugins segueixin funcionant.
He pogut comprovar de primera mà el que es diu a la web de Trac, "clearsilver sucks", ja que amb Ubuntu i la versió 2.5 de Python no fa sino donar problemes, que sospit han acabat per tomar el servidor Apache 2 que tenim al webhosting virtual. En un primer moment he pensat que se'ns hauria tornat a oblidar el pagament, però no, tots els serveis eren vius llevat de l'Apache i als logs he vist un bon munt d'errors del tipus
/usr/lib/python2.5/site-packages/trac/web/clearsilver.py:128: RuntimeWarning:No ha costat molt trobar referències tant al Trac com a Ubuntu d'aquest error i de com solucionar-ho. Aquesta és la recepta que m'ha servit a mi:Python C API version mismatch for module neo_cgi: This Python has API version 1013, module neo_cgi has version 1012.
- Davallam el codi font: wget http://www.clearsilver.net/downloads/clearsilver-0.10.4.tar.gz
- Modificam els arxius config i config.in, cercam les línees que diuen python_version i i afegint la versió 2.5 al davant.
- Descomprimim el fitxer tar xvzf clearsilver-0.10.4.tar
- Davallam paquets adicionals però aquesta vegada per apt-get
- sudo apt-get install zlib1g-dev
- sudo apt-get install autoconf
- sudo apt-get install python-dev
- Feim el configure: ./configure --disable-wdb --disable-compression --disable-perl --with-python=/usr/bin/python2.5
- I per acabar el sudo make install
- Com que la instal·lació no acaba d'anar fina convé copiar la llibreria generada sudo cp -i neo_cgi.so /usr/lib/python2.5/site-packages/neo_cgi.so per acabar de substituir la referència que hi havia de la llibreria anterior o fer un ellaç simbòlic cap a la nova instal·lació de clearsilver: sudo ln -s ./clearsilver-0.10.4-py2.5-linux-i686.egg/neo_cgi.so neo_cgi.so
Referències:
Traducciones/Translations by apertium
1 comentari, 0 trackbacks (URL) , Tags: Informàtica Python Gestió de projectes
Creant un tag per Django
Escrit per Aaloy a 14 de July , 2007 a les 9:33 p.m.
Una de les coses que fa Django potent com a bastiment és la seva extensibilitat, és força senzill extendre el llenguatge de plantilles amb nous filtres i nous tags.
Avui tenia la necessitat de generar un nombre aleatori, semblant a l'exemple d'Ajax d'un post anterior, pero aquesta vegada volia que no fos necessari cridar a cap vista.
Això seria molt senzill de fer passant el valor com a paràmetre, però pot servir com un exemple més de com crear els nostres propis tags.
Crear un tag en Django requereix de dues passes: crear la funció de compilació i crear la classe que renderitzarà el trag mostrant el text que volem.
Una vegada fet això basta registrar el tag i per això el mateix Django ja ens facilita un decorador.
La randomCode és la que agafa el tag i els paràmetres del tag i en far el parseig. En aquest punt hem de caçar els errors de sintaxi del tag i informar a l'usuari de com es fa server.
La classe randomCodeNode agafa el valor que li passa la funció anterior i fa les operacions necessàries per a tonar-nos una cadena de text presentable en una plana web.
L'esquelet ens pot servir com a base de tags molt més complexos, per exemple tags que incloguin automàticament llibreries javascript , o que facin més senzilla la seva utilització, ...
Per fer servir aquest tag n'haurem de carregar l'arxiu dins la nostra plantilla, com en el cas del filtres això se fa amb un {% load arx %} on arx és el nom de l'arxiu que conté el tag que acabam de crear.
from django import template import string import random CODE_CHARS = string.ascii_uppercase+string.digitsregister = template.Library()@register.tag(name="randomCode")
def randomCode(parser, token): try: # split_contents() knows not to split quoted strings. tag_name, num = token.split_contents() except ValueError: raise template.TemplateSyntaxError, "%r tag requires an integer as a single argument" % token.contents.split()[0] if not (num[0] == num[-1] and num[0] in ('"', "'")): raise template.TemplateSyntaxError, "%r tag's argument should be in quotes and be a positive integer" % tag_name try: value = int(num[1:-1]) if value <0: raise template.TemplateSyntaxError, "%r tag's argument must be a positive integer" except: raise template.TemplateSyntaxError, "%r tag's argument must be a positive integer" % tag_name return randomCodeNode(value)
class randomCodeNode(template.Node): def init(self, num): self.num = num def render(self, context): try: codi = random.sample(CODE_CHARS,self.num) except ValueError, e: raise template.TemplateSyntaxError, "tag's argument must be a lower than %i" % len(CODE_CHARS) s = '' return s.join(codi)
El Wordpress no és gaire bo amb el codi, podeu trobar-ho millor colorejat a Djangosnippets
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python Django
Depurar una aplicació Django
Escrit per Aaloy a 23 de January , 2007 a les 1:27 a.m.
De tant en tant faig algun apunt per tenir una referència posterior, a manera de documentació per tal de no oblidar-me de com se fa una cosa, d'una referència o procediment. Avui és un d'aquests apunts.
Com he comentat en altres apunts darrerament estic fent molta cosa amb Python i Django com a bastiment MVT web. En un món ideal el meu G5 funcionaria de conya amb l'Eclipse i tendria un depurador de Python integrat a l'IDE, però com que no tot pot ser tan meravellós com la combinació de Python i Django, doncs vaig tenir que cercar alternatives. Una prou bona és el Kdevelop, així que al G5 per programar utilitz les següents eines:
- Kdevelop com a Editor principal. Ben bé es podria fer amb Kate, però m'agrada la funcionalitat extra que aporta.
- Vim, no pot faltar mai!
- svn per interactuar amb el repositori subversion. També feia server kdesvn però al final m'és més còmode la línea de comandaments.
- kdiff3. Que la comparació visual està molt bé, tú!
- Firefox amb les extensions de webdeveloper tools i firebug
- Eclipse. Quan la gestió dels canvis se me complica i puc mantenir-ho estable el temps suficient per fer els canvis.
El problema d'això és si no es fa servir l'Eclipse no disposam de depurador integrat a l'IDE. [1]. Això per mi és un problema, menor, sí, perquè Python és prou net i elegant i la informació de depuració de Django prou extensa com per anyorar-ho poc, però què voleu, m'agrada al manco tenir l'opció de poder seguir la traça d'un programa sense tenir que tirar de logs i prints. [2].
Doncs mirant un poc pels fòrums de Django i un poc per Google, he arribat a la següent recepta:
- Executam el servidor de Django amb l'opció de noreload:
python manage.py --noreload runserver - Al fitxer el codi del qual volem depurar feim
from settings import DEBUG if DEBUG: import pdb - Per acabar al lloc on voguem posar el punt de ruptura escriurem:
pdb.set_trace()
L'important aquí és l'import, l'altre codi sols és per assegurar-nos que si ens deixam el codi de depuració en producció "petarà".
Això fa que en arribar a al punt hom hem establer la traça, la consola del servidor de Django ens mostri el símbol de depuració.
-> user = request.user
(Pdb)
A partir d'aquí ja hem entrat en mode de depuració i basta llegir-se un poc la documentació del depurador integrat de Python per anar tirant. Recordem que no estam sols davant d'un simple depurador, sinó que tenim tota la potència de Python al depurador mateix. Un tutorial força senzill per començar és Debugging in Python.
Una vegada acabeu de depurar hem de recordar llevar o comentar el pbd.set_trace(). Possiblement hi haurà maneres més potents de fer això, com la depuració remota, però aquesta és prou senzilla de fer anar. [1] Eric en duu un de depurador integrat, però darrerament no hi ha manera de posar-hi accents a l'editor i no es cosa sols del G5, així que l'he descartat de moment com a IDE.
[2] He vist gent no fer servir el depurador integrat de l'Eclipse programant en Java, però me'n reservaré l'opinió.
Traducciones/Translations by apertium
2 comentaris, 0 trackbacks (URL) , Tags: Informàtica Python Django
wxPython in Action
Escrit per Aaloy a 23 de May , 2006 a les 12:59 a.m.
Per la llista de Python, concretament a pun apunt del Dr. Dobb's Python-URL! m'he assabentat de l'existència del llibre wxPython in Action i de la possibilitat de fullejar un dels seus capítols a la web pythontrheads.
Això són bones notícies, ja que vol dir que a partir d'ara tindrem més documentació d'aquesta excel·lent llibreria gràfica. Pels qui no la coneguin wxPython és un embolcall (binding) per Python de les llibreries wxWidgets, abans conegudes com wxWindows. Aquestes llibreries són portables, potents i no gaire pesades. L'emperò és que la seva gestió d'events no és tan neta com el mètode signal/slot de les Qt.
Com a avantatge tenim els nombrosos exemples que hi ha per fer gairebé de tot el que se'ns acudi en termes d'interfície gràfica i dissenyadors d'interfícies d'usuari com les wxGlade, o un IDE com el Boa Constructor .
Les wxPython són una opció a tenir en compte si ens plantejam fer una interfície d'usuari que sigui lleugera i portable, i m'atreviré a afegir dues característiques més: mantenible gràcies a la claretat i senzillesa de Python i divertida de programar.
Traducciones/Translations by apertium
1 comentari, 0 trackbacks (URL) , Tags: Informàtica Python
Un Hibernate per Python.
Escrit per Aaloy a 23 de May , 2005 a les 11:16 p.m.
Fa estona que tenc ganes de fer una aplicació de gestió amb Python, així com a prova de concepte i per passar-m'ho bé programant.
Una de les coses que més m'aturen és el tema de la persistència. Ja sabeu, al final les aplicacions de gestió han de volcar les seves dades a una base de dades i això fa que es tengui que escriure i mantenir força codi SQL.
Darrerament he estat llegint molt damunt Java i hi estic començant a fer feina professionalment. Quan estàvem montant l'arquitectura que faríem servir per les aplicacions també va sorgir el problema de la persistència. Llavors una de les opcions que més m'agradaren per la seva potència i simplicitat va ser l'Hibernate.. Aquest bastiment de persistència m'agrada molt i fa que una de les tasques més propenses a errors i més tocacollons com és el d'escriure i mantenir codi SQL estigui molt més controlada.
Per Python estava cercant quelcom semblant i no l'acabava de trobar. Avui se m'ha acudit cercar servidors web per Python i he anat a topar amb SunkWeb. Pel que he estat llegint fins ara pot ser la resposta, cap dels bastiments de persistència que havia vist per Python tenen la bona pinta que té aquest. Si és tan potent com pareix aviat podré tenir alguna cosa feta.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python
The Daily Python-URL
Escrit per Aaloy a 30 de August , 2004 a les 2:50 p.m.
Pels qui encara no el conegueu i us agrada el llenguatge Python trobareu força interessant aquesta pàgina .
En ella es fa un resum de les notícies i novetats més interessants relacionades amb el món de Python. Molt recomanable si no us voleu perdre res.
Traducciones/Translations by apertium
0 comentaris, 0 trackbacks (URL) , Tags: Python
