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
Repetiu amb mi: KISS
Escrit per Aaloy a 08 de March , 2009 a les 10:35 a.m.
El principi KISS és una d'aquelles regles fonamentals en la programació i gestió de projectes. Ens diu que hem de procurar que el nostre producte, codi, projecte es mantengui el més simple possible, però contràriament al que algú es pugui pensar, això no implica pèrdua de potencia o funcionalitat, ben al contrari.
Fer les coses simples implica aturar-se a pensar en el que un està fent, demanar-se si hi ha una manera més neta de fer-ho, una manera més senzilla, i si hi és aplicar-la, està doncs molt relacionat amb un terme fonamental en la programació: la refactorització.
El problema doncs és adonar-nos de quan estam complicant les coses de manera innecessària i per això és necessari tenir la ment oberta, ja que sovint estam tan aprop del nostre propi codi que ens costa tenir la perspectiva suficient com per veure que el que estam fent es pot fer d'una altra manera.
Una de les maneres més efectives és intentar explicar a algú com funciona, com ho hem fet. Explicar implica recapitular, tornar a pensar en el que hem fet i encara que el nostre interlocutor no faci "carusses" potser ens trobarem reflexionant damunt la complexitat del que estam dient.
Una altra bona opció és documentar, l'aplicació , el codi. Quan documentam l'aplicació es fa una cosa semblant a l'explicació i té el mateix resultat, quan documentam el codi i ho rellegim ens podem adonar de la seva complexitat: si la documentació ha d'explicar com es fa en lloc de què fa el codi, segur que ens hem botat la regla KISS.
Si hi ha alguna cosa en aquest món que compleix el segon principi de la termodinàmica és el codi i els programes. Esforçar-se en fer les coses de la manera més simple ens proporciona un punt de partida que ens permetrà allargar la vida del codi i disminuir-ne el temps de manteniment. Hem de tenir clar que l'entropia és una força de l'univers, no podem guanyar, però podem fer que el desastre arribi més tard.
Però la regla KISS no s'aplica sols al codi, l'hem d'aplicar també als projectes i també se l'haurien de fer seva els usuaris. Mantenir un projecte simple implica fugir de funcionalitats innecessàries, saber quan hem d'aturar i limitar l'abast del projecte. Per això també ens serà d'ajuda un altre acrònim: MOSCOW. La simplicitat al projectes és doncs poder destriar bé el gra de la palla, el que és necessari i el que no.
Els programadors tenim tendència a afegir funcionalitat "per si un cas", codi que no sabem si s'utilitzarà mai, i que potser el que estigui fent és limitar-nos en el futur. Potser l'allau de funcionalitats és quelcom que fa vendre el producte, quantes vegades hem vist com es llancen versions noves de programari que mantenen els mateixos errors però amb noves funcionalitats! Però en el programari desenvolupat per ser utilitzat per l'empresa, mantenir-se dins del necessari implica menor cost inicial i menor cost de depuració i manteniment.
De fet, quan s'ha de pressupostar el cost d'un projecte es distingeix entre projectes que s'utilitzaran sols a l'empresa dels projectes que s'han de distribuir massivament. Els segons tenen un cost molt més elevat, ja que tenim la necessitat d'una depuració més exhaustiva i també perquè sabem que aniran carregats de funcionalitats sols necessàries per a vendre el producte.
Sovint quan desenvolupant programari d'ús intern caiem en el parany de voler tractar-ho com si fos programari de venda comercial. El programari que desenvolupam per al client intern ja el tenim venut, no hi ha d'haver un marketing basat en les n-mil característiques que fa més respecte la competència, sinó en la funcionalitat que dóna, en la diferència de cost o de control que ens dóna fer les coses amb el nou programari en lloc de fer-ho com es feia abans. Això vol dir, concentrar-se en el fonamental, mantenir el programa simple i funcional des del principi, ja que amb l'us segur que s'anirà complicant, no ho compliquem de sortida.
A la gent que ens comana el projecte els hauríem de fer partíceps de la regla KISS, fer-los conscients de la importància de separar l'essencial de l'accessori, del cost que suposa complicar innecessàriament les coses.
Fer les coses simples és molt complicat, no hi ha dubte, és més senzill fer-les complexes sense pensar en les conseqüències, però llavors voldrà dir que no estam fent bé la nostra feina.
Traducciones/Translations by apertium
1 comentari, 0 trackbacks (URL) , Tags: Gestió de projectes
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
