Django-request , ne partez plus en quest de vos stats

Et non, vous ne rêvez pas, on est même pas le 15 avril et déjà, déjà, le billet de l’app django du mois est là. Mais bon, les rencontres django ayant lieu dans maintenant 14 jours et n’ayant pas encore commencer à préparer ma conf, même pas le premier mot (enfin si, bonjour), ce qui fait que je suis ‘dans la banade’, comme l’a fait si justement remarquer il y a peu @daks_

Donc, je préfère me ‘débarrasser’ tout de suite de l’app du mois, comme ça, ça sera au moins une chose de faite.

Ce mois-ci, je vais donc vous présenter django-request, une app pour faire des stats sur la fréquentation de votre django. Oui je sais il y a google analytics pour ça. Mais bon, on sait jamais, ça peut être utile quand même.

1- Où on le trouve, comment on l’installe, tout ça quoi (et la doc) ?

On le trouve à deux endroits :

A noter que quasiment toute la doc se trouve être sur la partie dédiée à django-request sur le site de son auteur.

Pour l’installation, facile, un git clone, un téléchargement de source ou alors pip et easy_install.

Quand à la doc, elle est vraiment très fournie et complète, permettant d’installer, de configurer, d’utiliser, la totale quoi.

2- A quoi ca sert ?

Ben à faire des stats, je l’ai déjà dit. Qui ne seront visibles que dans la partie admin.

On peut avoir de jolis graphiques concernant :

  • les visiteurs uniques
  • les visites basées sur des referrer différents
  • les requêtes reçues par le serveur
  • les requêtes venant des moteur de recherches
  • les requêtes provenant du javascript
  • les requêtes en SSL
  • les requêtes faites par un utilisateur
  • le nombre d’erreur 404
  • le nombre d’erreur, toutes erreurs comprises
  • le nombre d’utilisateur enregistré sur le site qui ont fait des requêtes

Par défaut les calculs seront fait pour les visiteurs uniques, les visites en fonctions des referrers et le nombre global de requêtes.

On obtient ensuite un joli petit graphique qui nous donne tout plein d’infos. Et plein de petits tableaux pour en avoir encore plus.

Et on peut même avoir, des petits templates tags pour voir les users actifs sur le site

3- Comment ça marche ?

Il suffit d’ajouter ‘request’ dans ses installed_apps et d’ajouter le middleware qui va bien. (Attention suivant les middlewares déjà installés, la position du middleware de django-request, dans le tuple des middleware est importantt, mais c’est bien expliqué dans la doc).

Ensuite, tout ce passe dans l’interface d’admin

4- Tips de chez Jmad.

Quand j’ai installé le tout avec easy_install, j’ai oublié de rajouter les chemins pour avoir les templates admins de l’app. Résultat je n’avais rien dans l’admin. Faites y attention ou alors installez request directement dans votre projet django, comme une de vos apps.

Le model Request présente un champ language qui est modélisé en bd par un varchar de 25. Avec mes tests, cette longueur était bien trop petite pour mon firefox. Du coup boum une erreur BD a base de ‘machin qui a été truncated’. J’ai passé la taille du champ à 200 pour être tranquille.

Les différents fichiers js qui sont utilisés sont bien entendu fournis. Pourtant par défaut, les templates vont utilisés ceux hostés ailleurs (sur le site web de l’auteur par exemple). N’oubliez pas de changer cette option si cela vous dérange.

C’est expliqué dans la doc, mais je le redis ici. Une fois que tout est bien configuré, pour aller voir ces stats, vous allez dans l’admin, vous cliquez sur la ligne Request de l’app Request. Là vous avez la liste de toutes les requêtes. (pas très utile là comme ça, vous me direz). Levez les yeux, en haut à droie, à coté du bouton Add Request, vous avez un bouton Overview. Et voilà, cliquez, vous avez vos stats.

Lancement d’un side project : Histoiresderolistes.com

‘C’est l’histoire d’un mec …’ qui était rôliste.

Bon ok, c’était facile, mais je trouve que c’est une bonne façon de démarrer ce billet. Billet tout entier consacré à de l’autopromo ou plutôt à l’annonce du lancement d’un de mes side-project comme on dit.

Histoiresderolistes.com. Né d’une idée toute simple à savoir que les rôlistes, dont je suis, adorent se raconter leur vieilles histoires de joueurs, leurs souvenirs de catastrophe évitées ou de justesse, ou pas du tout, leur grand moment de rigolade. Et parfois on a envie de partager ces histoires, pas seulement avec son groupe de joueur actuel, mais avec ses anciens compagnons de parties, ou même avec d’autres rôlistes tout court.

Comme je n’ai pas trouvé un tel endroit, je me suis dit que j’allais la bâtir moi même, la petite taverne virtuelle où nous pourrions tous être barde, le temps d’une histoire.

Alors ce ne fut pas facile de venir à bout de ce projet, dont la taille est pourtant plus que petite. Pour donner une idée de la chronologie :

  • j’ai eu l’idée du site en juillet 2009, j’ai aussitôt acheté le nom de domaine
  • j’ai commencé à aligner quelques lignes de code en aout (merci les vacances), mais ayant du boulot du boulot, en retard, j’ai que très peu avancé.
  • Je m’y suis vraiment mis fin janvier/début février en essayant de trouver du temps la nuit et les week-ends.
  • le week-end de Pâques m’a permis de finaliser le tout et de faire tester à quelques chanceux (merci les gens de #djangocong et du plug).

Mais maintenant, il est en ligne, et vous pouvez aller y lire/raconter des histoires de rôlistes. Et si il est en ligne, c’est aussi grâce à ma chére et tendre qui a été la première des béta testeuses, bien qu’elle ne soit pas du tout rôliste… Le fait qu’il n’y est pas de fautes d’ortographes sur le site (ou presque pas) est par exemple complètement grâce à elle, mais ce n’est pas son seul apport, loin de là.

Et ce n’est pas qu’un ‘simple’ site où les gens soumettent des histoires. Quitte à lancer un truc, autant s’en servir comme bac à sable, pour tester des choses dont je parle dans mes billets.

Comme par exemple, l’introduction de mécanismes tirés des jeux vidéos, comme les titres et succès (qui sont ici appelés badges).

Vous pourrez donc gagner des titres (top posteur par exemple) ou des badges comme le badge du djinn narcissique ou du gobelin fanatique (liste des badges). Exactement comme dans les jeux, vous ne connaitrez pas la manière de débloquer certains badges. Parfois même, vous ne saurez même pas que les badges existent avant de les débloquer.

Ce n’est bien entendu qu’un début, j’ai plein d’autres idées (dont certaines déjà listées dans les billet du ce blog), que je mettrais en place petit à petit. En essayant, ensuite, d’analyser le retour des utilisateurs à mes ‘expériences’.

Mais déjà, la question est de savoir si h2rolistes (et il y a même un twitter et un identi.ca pour suivre les nouveautés) va trouver son public ou non…

Et bien entendu, h2rolistes c’est du 100% django.

Petit mémo concernant la syndication Django

Ce billet n’est qu’un petit mémo rapide, pour éviter que d’autre perdent comme moi du temps à chercher un problème qui n’en est pas un. Si jamais je me trompe dans mon interprétation du problème et dans la solution que j’en donne, je suis preneur d’une explication / correctif dans les commentaires.

Django embarque, dans les contrib, un petit framework pour géré la syndication. Plutôt bien foutu d’ailleurs.

Il fonctionne suivant un principe assez simple, pour chaque flux on définit une classe, ensuite on range les classes dans un dict où la clé sera le nom du flux dans l’url et la valeur, la classe, que l’on passe en paramètre à la vue qui gère l’ensemble des flux. (tout est parfaitement expliqué dans la doc, ici).

Par exemple :

from django.conf.urls.defaults import *
from myproject.feeds import LatestEntries, LatestEntriesByCategory

feeds = {
'latest': LatestEntries,
'categories': LatestEntriesByCategory,
}

urlpatterns = patterns('',
# ...
(r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed',
{'feed_dict': feeds}),
# ...
)

ici on aura donc deux urls :

  • /feeds/latest
  • /feeds/categories

On peut définir deux templates celui pour justes les titres et celui pour l’item RSS complet. Les deux templates doivent avoir pour nom :

  • KeyDict_title.html
  • KeyDict_description.html

Soit dans notre exemple :

  • latest_title.html
  • latest_description.html
  • categories_title.html
  • categories_description.html

Et tout fonctionne parfaitement dans le meilleur des mondes.

Maintenant prenant un exemple un peu plus compliqué. Imaginons deux apps django, une pour gérer un blog, une pour gérer des reviews de films.
Les deux apps vont donc mettre en place des flux RSS, logique.
Et les deux vont vouloir mettre en place le flux latest. Donc dans chaque répertoire templates des apps, il y aura un sous-répertoire feeds avec les fichiers latest_title.html et latest_description.html

Et là, patatra. Le deuxième flux (dans l’ordre des INSTALLED_APPS) va utiliser les fichiers templates du premier. Parce qu’apparement la recherche des templates pour les feeds et transversale.
Donc faut nommer de manière différentes ses flux. latestblogs et latestreviews par exemple.

Et là, miracle, ça fonctionne.

Voilà, c’est tout.

Petits tours des méthodes des querysets.

Les queryset sont une des composantes importantes de Django. Comment en effet interagir avec la BD sans eux ?

Mais est ce que cet outil si important et si souvent utilisé est si bien connu que ça ?

Parce que tout le monde connait count(), filter(), all() et exclude(). Mais qu’n est-il des autres méthodes ? Perso, je suis le premier à aller dans la doc, pour revérifier si ce que je voudrais n’existe pas déjà…

C’est le pourquoi de ce billet, lister quelques méthodes ‘à connaître’ des querysets (et puis comme ça la prochaine fois que j’aurais besoin de vérifier un truc, je pourrais le faire en lisant du français et pas de l’anglais). (Ce n’est au final qu’une redite de la page de doc qui va bien, mais ça peut servir).

1- Les méthodes qui renvoient un queryset (ou assimilés)

annotate(*args, **kwargs)

une petite méthode bien pratique, qui permet de rajouter des colonnes calculées (en utilisant les classes d’agrégat Sum,Count, etc défini par django) pour chaque objets récupérés dans le queryset.

Et ça, c’est plutôt fort. Surtout que l’on peut, bien entendu, ‘traverser’ les foreign key
L’un des exemples de la doc, montre cela en calculant pour un magasin le prix minimum et maximum des livres en vente :

Store.objects.annotate(min_price=Min('books__price'), max_price=Max('books__price'))

values(*fields) et Values_list (*fields)

Deux méthodes plus que miam.
Values retourne un ValuesQuerySet qui est en fait un queryset composé d’une liste de dictionnaires au lieu d’une liste d’instance d’objet modèle. Chaque dictionnaire représente un objet, les paire clés / valeur représentant le nom de l’attribut (la key) et la valeur de l’attribut (sa valeur).
On peut passer à values un paramètre optionnel *fields, qui permet de spécifier la liste des noms d’attribut (des strings donc) que l’on veut récupérer.
Exemple :

>>>Blog.objects.values()
[{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}],
>>> Blog.objects.values('id', 'name')
[{'id': 1, 'name': 'Beatles Blog'}]

Deux choses importantes à se rappeler, values ne récupère rien pour les manytomany et dans le cas des FK, la clé du dico est le nom ‘vrai’ de l’attribut dans la table (souvent avec _id donc) et la valeur, la valeur de la PK de la FK. Et comme le voit dans l’exemple, si on veut passer le nom explicite de l’attribut de la fk, on peut au choix mettre ou pas le _id, le résultat est le même.

Exemple :

>>> Entry.objects.values()
[{'blog_id: 1, 'headline': u'First Entry', ...}, ...]

>>> Entry.objects.values('
blog')
[{'
blog': 1}, ...]

>>> Entry.objects.values('
blog_id')
[{'
blog_id': 1}, ...]

values_list c’est à peu près la même chose que values, sauf que c’est une liste de tuple et pas une liste de dico. On peut en plus lui passer un paramêtre flat que l’on peut mettre à true , pour ‘aplatir’ les tuples quand l’on demande qu’un seul champ (juste coolos quand on veut une liste de pk)

>>> Entry.objects.values_list('id').order_by('id')
[(1,), (2,), (3,), ...]

>>> Entry.objects.values_list('id', flat=True).order_by('id')
[1, 2, 3, ...]

A quoi sert values et values_list ?

L’intérêt c’est qu’un ValuesQuerySet, c’est comme un queryset. Et que donc on peut utiliser toutes les méthodes des queryset dessus. Y compris refiltrer, order_by, etc etc ..

Et que dans le même temps, on peut alléger la charge, surtout si on a des gros models dont l’on ne veut utiliser que quelques champs.

defer (*fields)

Permet d’indiquer au queryset de ne pas récupérer automatiquement le contenu des champs qui sont passés en paramêtre du defer. Ca peut être utile dans le cas de gros champ texte par exemple (imaginons une vue en liste de billet de blog où l’on ne veut que les titres des billets et pas leur contenu, utiliser un defer(‘body’) pourrait être une possibilité , utiliser un values en serait une autre)

les champs deferred seront récupérés quand on les appelera explicitement. Pour annuler les defer d’un queryset, il suffit d’appeler la fonction avec None en paramêtre.

only (*fields)

C’est l’inverse du defer, on ne récupère que certains champs.

2- Les fonctions qui ne renvoient pas un queryset.

in_bulk(id_list)

Cette petite fonction bien sympa prend une liste de pk et renvoie un dico des objets qui correspondent (les clés étant les pk)

latest(field_name=None)

Renvoie le dernier objet, inséré dans la base, en se basant sur les dates et en utilisant le champ passé en paramètre (qui doit donc être un champ  date).
Si le model en question définit la Meta get_latest_by, on peut appeler latest sans argument.

Ok, cette fonction ‘ne sert à rien’ à part pour rendre plus lisible le code. Mais bon, ça ne mange pas de pain. Et l’utilisation de la Meta get_latest_by permet de ‘centraliser’ la façon de rechercher le dernier, ce qui rendra une modification plus facile.

aggregate(*args, **kwargs)

Retourne un dico des valeurs d’aggrégat calculés non pas objet par objet comme avec annotate, mais sur tout le queryset.

A vous les sommes de champ, les moyennes ou autre. Vive les rapports :).

>>> q = Blog.objects.aggregate(Count('entry'))
{'entry__count': 16}
>>> q = Blog.objects.aggregate(number_of_entries=Count('entry'))
{'number_of_entries': 16}

et comme pour annotate, on peut contrôler le nom, ici de la clé, que notre valeur calculée.

exists()

cette fonction n’existe pas encore dans django, elle sera présente dans la 1.2. Elle permet tout simplement de savoir si le queryset est vide ou pas. (oui je sais, devoir attendre la 1.2 pour avoir cette fonction.. mais bon 🙂 ).

Django-rosetta, parce que pierre qui roule n’amasse pas mousse

Vous aimez mon titre ? Parce que moi, j’en suis super fier en fait. Et oui, il m’en faut peu. Bon donc pour la django-app du mois de février, j’avais choisi django-transmeta qui permettait de traduire facilement son contenu. Mais un site n’est pas fait que de contenu, il est aussi fait de label, de menu, de tout plein de truc qu’il faut internationaliser à coup de .po et de .mo. Ce qui est, il faut bien le dire, un poil chiant. Limite je pourrais dire, qu’à vouloir traduire tout ces mots, on pourrait bien finir par y laisser notre peau.

C’est là que django-rosetta intervient.

1- Où on le trouve, comment on l’installe, tout ça quoi (et la doc) ?

Comme bien souvent, sur la page qui lui est destiné, qui est, un google code. Pour l’installation, rosetta fait dans le rustique : tar.gz ou svn checkout. Brut mais efficace.

Ensuite il suffira de rajouter django-rosetta dans les INSTALLED_APPS  et de rajouter ses urls dans l’urlpattern qui va bien. Et c’est tout, après roule ma poule (ou ma pierre, de rosette HA HA).

Pour la doc, la encore, il n’y a que la page home du google code. Mais l’app est suffisament bien faite, pour que la doc présente soit amplement suffisante.

2- Comment ça marche ?

Django-rosetta vous permet de rendre la rédaction des .po moins chiante que dans un simple gedit. Mais du coup, cela veut dire que l’application a besoin d’avoir les permissions d’écritures sur certains des fichiers de votre arborescence.

Du coup, elle n’est utilisable que de l’admin django. C’est un choix qui me semble, en fait, très logique. Et puis est ce que cela existe des gens qui n’utilisent pas du tout la partie admin de django ?

Ensuite, c’est tout simple, on a une liste des fichiers po, avec les pourcentages de traduction effectuées. On en choisit un et on se met au boulot. On peut même choisir si l’on veut afficher toute s les chaines ou que celle que l’on n’a pas encore traduite.

Allez op, deux petites images pour vous montrer le truc, parce que je suis gentil. (Et puis que je ne me suis pas trop fatigué, je reprend honteusement celles du google code officiel).

Voilà, avec cette deuxième app, j’en ai fini de parler, en tout cas pour un temps, d’internationalisation. A bientôt (dans un mois) pour de nouvelles découvertes dans le merveilleux pays des app django.

Django-transmeta ou comment traduire son contenu sans se faire suer

Et oui, vous ne rêvez pas, malgré le fait que le mois de février soit ridiculement court, je trouve tout de même le temps d’écrire mon billet de l’app django du mois. Comme quoi, tout arrive.

Bon il faut dire, que j’ai du coup sélectionné une app assez petite, que j’ai découvert grâce à #django-fr (merci les gars) et avec une doc très bien conçu que je vais donc pouvoir honteusement recopier en parti pour vous expliquer comment cela fonctionne.

1- Où on le trouve, comment on l’installe, tout ça quoi (et la doc) ?

Sur la page qui lui est dédiée sur google code. Et pour l’installer, point de tar.gz, de easy_install ou de pip. Le seul moyen de l’installer consistera à faire un bon vieux svn checkout des familles.

Au niveau de la doc, il n’y a que la page du project home du google code. Mais par contre, elle est super bien foutue.

Rendre heureux aussi, ceux qui ne parlent pas français (personne n’est parfait 🙂 ).

Django-transmeta tente de répondre à un besoin tout con, comment traduire efficacement son contenu, lorsqu’on a un site multi langue. Parmi tout les moyens imaginables pour faire cela (j’en reparlerais en fin de billet), transmeta a choisi de modifier directement les tables des modeles à contenu traduisible.

2- Comment ça marche ?

Je vais reprendre, texto, les exemples donnés par la page web de transmeta, parce qu’ils très clairs. Prenons l’exemple d’un model qui décrit un bouquin.

Tel que :

class Book(models.Model):
title = models.CharField(max_length=200)
description = models.TextField()
body = models.TextField(default='')
price = models.FloatField()

Là, rien n’est traduisible. Imaginons que l’on veuille traduire la description et le body. Rien de plus simple, le code du model devient alors :

class Book(models.Model):
__metaclass__ = TransMeta

title = models.CharField(max_length=200)
description = models.TextField()
body = models.TextField(default='')
price = models.FloatField()

class Meta:
translate = ('description', 'body', )

On rajoute une metaclass et on défini dans la classe méta, les champs que l’on veut traduire.

Il faut ensuite, dans le settings.py, définir les langues que l’on veut gérer, par exemple :

LANGUAGES = (
('es', ugettext('Español')),
('en', ugettext('English')),
)

Et qu’est ce que cela fait ?
Un petit manage.py sqlall va vous le dire :

CREATE TABLE "fooapp_book" (
"id" serial NOT NULL PRIMARY KEY,
"title" varchar(200) NOT NULL,
"description_en" text,
"description_es" text NOT NULL,
"body_es" text NOT NULL,
"body_en" text NOT NULL,
"price" double precision NOT NULL
)
;

apparaît ici la solution utilisé pour transmeta. Chaque champ qui est défini comme traduisible donne lieu à n champs en bd, pour n langues.

Là vous allez me dire : ‘Ok, bien cool, mais comment on fait quand on rajouter une langue ou que l’on veut faire en sorte qu’un champ existant qui n’était pas traduisible le soit ?’
Forcément, c’est prévu. Sinon, je n’aurais pas osé faire de billet. Donc il y des commandes manage.py spécial pour altérer les tables déjà existantes et permettre de rajouter soit des langues, soit des champs traduisibles.
Dernière chose, il y a tout ce qu’il faut de prévu pour pouvoir gérer ses champs dans l’admin.

3- Retour sur la méthode

Le principe de fonctionnement de transmeta implique de devoir utiliser des alter table à chaque fois que l’on veut rajouter une langue ou un champ. J’avoue que je n’ai jamais aimé les alter table sur du sql. Est ce un tort que j’ai ? Je ne sais pas.
Vous me direz que si l’on utilise pas d’alter table, on se retrouve presque les mains liées et qu’il ne reste que peu de solution, à part des grosses tables sous la forme ‘langue code’, ‘field name’, ‘trad’. Il est vrai. Mais bon, j’aime pas les alter table.

4- Retour sur le titre du billet :

Tout le monde aura compris, bien entendu, le jeux de mot. C’est une référence directe à transmeta, l’entreprise américaine qui faisait des processeurs ni ne chauffaient que très peu et qui donc n’avait pas besoin de ventilo. D’où le sans suer. C’est nul, je sais.

Ajouter ses filters perso aux filters builtins

Vu le manque de temps dont je souffre, je n’ai pas vraiment le temps d’écrire de long billet. J’espère pouvoir changer cela assez vite. Mais en attendant, une petite astuce que j’ai découvert il y a peu et que pour l’instant, je dois l’avouer, je n’utilise pas beaucoup. Mais ça peut-être utile.

Django offre deux outils merveilleux pour bosser avec ses templates, les templatetags et les filter. J’en utilise à tour de bras, sans arrêts.

Ce qu’il y a d’ennuyeux, il faut bien le dire, c’est dans le cas où l’on utilise un filter, dans tout les templates, de devoir faire, dans chaque template le {% load myfilter %}

Sachant qu’en plus si j’inclus un template A dans un autre B, le template A ‘n’hérite pas’ des filters et templatetags qui ont été déclaré dans B. Je devrais donc de nouveau dans A me refrapper les {% load ..

Pas de quoi raler plus que ça, je vous l’accorde.

Mais quand même, ce n’est pas très DRY tout ça, si on doit faire un load dans tout les templates de son appli.

Heureusement, papi Django a pensé à nous. Et il y a la possibilité de déclarer un filter comme étant un builtins. Il sera donc inclus par défaut, dans tout les templates.

Comment on fait ce petit miracle ? Rien de plus facile. Il suffit de mettre quelque part dans son code (dans l’__init__ de son app par exemple ) :

from django.template import add_to_builtins
add_to_builtins('nom_app.templatetags.nom_fichier_filter')

C’est tout de même assez facile, non ?

Par contre, je pense qu’il ne faut pas abuser de cette petite astuce, je soupçonne une diminution des perfs possible dans le cas d’une utilisation sans modération.

Unpacking de tuples dans les templates django

Il peut arriver que l’on est besoin de passer à ses templates des données sous la forme de tuple. Mais comment dans le template, récupéré les données qui sont dans le tuple ?

Question importante s’il en est.

Je vous rassure tout de suite, là réponse n’est pas ‘construire une classe qui sert à rien pour pouvoir faire instance.nom_donneée_membre. ‘

Il y en en fait deux méthodes.

Méthode 1

on peut unpack (désolé je n’ai pas trouvé de traduction françaises pour unpack) les tuples en utilisant la notation .NumeroChamp. Petit exemple :

tuples = [ ( foo, barr, tut ) , ( a , b , c ) , ( x, y , z ) ]

{% for tuple in tuples %}
    {{ tuple.0 }} {{ tuple.1}} {{ tuple.2 }}
{% endfor %}

C’est déjà pas mal, mais c’est peu lisible. Il y a donc mieux, la méthode 2.

Méthode 2

Celle ci permet d’unpack directement vos tuples dans la boucle for, en donnant un nom à chaque variable. Dans ce cas là, il faut donc que chaque tuple est la même structure.

Imaginons par exemple que l’on construit des liens à la volée, avec des tuples qui contiendraient deux champ, l’url et le nom du lien, on aurait donc :

{% for url , name  in tuples %}
    <a href="{{url}} "> {{name}}</a>
{% endfor %}

Plutôt sympa non ?

Django 1.2 beta, the news

Comme le petit billet qui listait les nouveautés de la version alpha de django 1.2 a eu un petit succès, j’ai décidé de récidiver et de faire la même chose pour la sortie de la version beta. Ce qui sera d’ailleurs beaucoup moins fatiguant, vu qu’il y a peu de nouveautés entre l’alpha et la toute récente beta.

Pour ceux qui veulent les releases notes précises, en anglais, c’est par ici, sur le site de django.

1- Trucs obsolètes ou changés.

1.1 Le lanceur de test

Le lanceur de test passe dans un modèle class-based. L’ancien style fonctionne encore mais il faut penser à passer dans le nouveau style.

1.2 La Syndication

La classe qui Feed qui gère les feeds a été modifiée (mais elle garde le même nom) et en plus elle change de package. De django.contrib.syndication.feeds.Feed elle devient django.contrib.syndication.views.Feed. L’api du truc ne change pas vraiment, mais maintenant on peut l’utiliser dans des vues.

De plus un atom:link apparaît, pour être en concordance avec les RSS best practices.

1.3 Encodage de cookies

L’ancien encodage des virgules et des points virgules bugguaient dans certain navigateur (IE par exemple..) Du coup, l’encodage a été changé.

2- Ce qui est complètement nouveau dans la beta

Tout d’abord, il faut savoir que la sortie de cette beta marque le gel des nouveautés dans la 1.2. Et non. Plus rien de nouveau. Il n’y aura plus maintenant que de la correction de bug (ma bonne dame). Mais en attendant, cette beta amène quand même quelque nouveautés.

2.1 Les permissions par objet

Ce n’est pas géré directement par le système par défaut de gestion des permissions. Mais cette beta permet maintenant à des systèmes tiers de gestion de permissions, de mettre en place un système de gestion de permissions par objet. Et ça, ça tue. (Pour être exact, ce système était déjà présent dans l’alpha mais pas documenté du tout).

2.2 Les permissions pour les anonymes.

Encore une modification du système d’authent / droit d’accés, qui permettra au système tiers de gestion d’authenfication, de gérer les droits pour les utilisateurs anonyme. Cette nouveauté permet de centraliser et d’homogénéiser les choses.

2.3 le select_related () passe à la gonflette

Peut-être grâce au pouvoir du glaive ancestral, ou peut-être juste à un gentil codeur core-team django, en tout cas, maintenant, le select_related accepte les related_name en paramètre.

3- Conclusion

Et voilà, c’est ‘déjà’ fini… Mais bon, je trouve que ça fait déjà pas mal de nouveautés (et de nouveautés utile en plus) pour une version beta. Pour la roadmap, rien n’a changé :
RC autour du 2 mars
version finale autour du 9 mars.

Il ne me reste donc plus qu’une seule chose à ajouter : Vivement le mois de mars.

je dois bien avouer que j’avais prévu d’insérer ici un proverbe concernant le mois de mars… mais malheureusement après une rapide recherche google j’ai eu le choix entre :

  • Pluie de mars ne vaut pas pisse de renard.
  • Mars qui rit malgré les averses prépare en secret le printemps
  • Au mois de mars, pluie et vent fou, sur nos gardes tenons-nous.
  • Mars en brume, mois de mai enrhume.
  • D’autre que je vais vous épargner.

Je ne finirais donc pas par un proverbe de mars. Tant pis.

Tagcon, où comment écrire simplement les templatetags, cong !!

Oui, je sais, je devrais renouveler un peu mon stock de blagues. Parce que mettre des cong à la fin de tout et n’importe quoi, pour singer l’accent marseillais, ça commence à …. Je sais. (j’en profite pour vous rappeler que le 24 et 25 avril, il va y avoir la DjangoCong à Marseille, une super convention fr où ça va parler django, encore et encore).

Et, oui, la django-app du mois de janvier arrive vraiment sur le fil, à quelques heures du dépassement de délai. Mais faudra dire ça au crétin qui a décidé qu’une journée ça ne serait que 24h et qu’il fallait obligatoirement dormir chaque nuit, ou presque … (bordeille comment je vais faire en février moi..)

Enfin, je reste dans les délais, c’est le principal. Et pour le deuxième mois consécutif, je fais une petit entorse au principe de cette catégorie, vue que ce mois-ci, encore une fois, ce n’est pas une vrai django-app que je présente, mais un ‘simple’ module python.

0- Et ça sert à quoi  ?

En fait tagcon est ‘inutile’ (donc indispensable vous allez me dire… ne niez pas, je vous ai tous entendu le dire…). Il sert simplement à faciliter l’écriture des templatetags (et surtout des templates tags à argument). On pourrait se dire que c’est assez inutile. Mais en fait, ça permet de gagner un peu de temps et de réduire d’une façon assez intéressante la taille de son code. Donc..

Un petit exemple, tiré de la doc, parce que comme me l’a fait remarquer daks (dont je conseille le blog, qui vient d’arriver dans mes RSS) , ça manque :

from django.contrib.auth.models import User
from django.template import Library
import tagcon

register = Library()

class UserListTag(tagcon.TemplateTag):
    limit = tagcon.IntegerArg(default=10)

    def render(self, context):
        self.resolve(context)
        yield "<ul>"
        for user in User.objects.all()[:self.args.limit]:
            yield "<li>%s</li>" % (user.username,)
        yield "</ul>"

1- Où on le trouve, comment on l’installe, tout ça quoi ?

Alors alors, sur le github qui va bien. (une petite remarque qui a rien à voir, je préfère de loin bitbucket à github … et pas juste parce que mercurial c’est mieux que git).

Une fois qu’on a récupérer le package (par fork si on a un compte github ou avec un petit tar.gz), il y a deux façon de l’installer:

  • un petit python setup.py install
  • en copiant directement le fichier base.py qui se trouve dans tagcon.tagcon (dans ce cas là on pourra renommer base.py en tagcon.py).

2- La documentation.

Alors là… Il n’y a pas grand chose. Un fichier readme qui donne un petit exemple et c’est tout. Après, il vous faudra lire les tests et le fichier source directement. Ce n’est pas donc super fourni, mais d’un autre coté, vous me direz que le module est tellement simple que ça suffit. Et vous ne seriez pas loin d’avoir raison. Mais bon.

3- En conclusion

Au départ, quand j’ai découvert ce petit module (je crois que je dois, encore une fois, remercier benoitc pour cela), je n’étais vraiment pas convaincu de son utilité. Il me semblait presque inutile et puis un peu restrictif en obligeant à utiliser la fonction render (alors que j’ai plus l’habitude d’enregistrer les fichier template html avec le décorateur inclustion_tag). Mais au final, on se ren compte que ça simplifie pas mal les choses et on y prend rapidement goût.

4- dernier paragraphe complètement HS.

Ma liste de django-app à tester est loin d’être vide (avec entre autre piston, haystack,..) et ça ne risque pas de changer, vu que chaque semaine, je découvre une nouvelle app. Toutefois, j’écris ces billets avant tout pour qu’ils soient utile . Donc, si vous connaissez des app que vous adorez et que vous aimerez faire découvrir à tous. Laissez moi leur nom en commentaire et je m’efforcerais de les tester.

Où les middleware envahissent la django-application du mois

Je sais, je suis impardonnable, je n’ai pas fait de billet sur la django-application de décembre. Vous pourriez même rajouter que je le suis encore plus parce que décembre c’est le mois des vacances de Noël et que qui dit vacances dit temps pour écrire un billet.

Oui, mais non. Parce que faut pas croire, ça prend du temps tout ces repas de fêtes. Plein de temps. Sans compter le temps que l’on passe à arpenter les magasins (IRL ou sur le net d’ailleurs) pour trouver des cadeaux. Et sans parler du fait que comme décembre est un mois de vacances, pendant les jours de non-vacances, faut bosser encore plus pour essayer de faire autant que pendant un mois normal, mais en moins de jours.

Autant dire que non, je n’ai pas eu le temps pour la django-app du mois.

Et que vu mon emploi du temps en janvier, ça va être tendu pour le billet de celle de janvier. Mais, mais, dans ma grande mansuétude, j’ai décidé de faire un billet de django app du mois de décembre, en retard.

Et pour une fois, je ne parlerais pas de django-app, mais de middleware. Mais oui, les middleware django, vous savez, ce mécanisme génial qui permet de pluger de petit bout de code à différents niveaux de traitement des requêtes. Ce qui permet de modifier plus ou moins profondément le comportement de django au niveau de la gestion de ses entrées / sorties.

Ca permet de faire plein de trucs, et plus encore.

Aujourd’hui je parlerais de deux d’entre eux, un que j’utilise très souvent et un autre que je vais utiliser sous peu..

1- Loguer les requêtes SQL que fait django

from django.db import connection
from django.template import Template, Context
from django.conf import settings

#
# Log all SQL statements direct to the console (when running in DEBUG)
# Intended for use with the django development server.
#

class SQLLogToConsoleMiddleware:
    def process_response(self, request, response):
        if settings.DEBUG and connection.queries:
            time = sum([float(q['time']) for q in connection.queries])        
            t = Template("{{count}} quer{{count|pluralize:"y,ies"}} in {{time}} seconds:\n\n{% for sql in sqllog %}[{{forloop.counter}}] {{sql.time}}s: {{sql.sql|safe}}{% if not forloop.last %}\n\n{% endif %}{% endfor %}")
            print t.render(Context({'sqllog':connection.queries,'count':len(connection.queries),'time':time}))                
        return response

J’ai trouvé ce tout petit middleware sur djangosnippets. Il se contente d’afficher la liste de toutes les requêtes SQL faites par django, en donnant le temps pris par leur execution.

C’est bien utile pour vérifier que ces vues ne font pas de la merde et pour tenter d’optimiser en factorisant des choses.

2- Django-maintenancemode

Celui-là, je l’ai découvert au détour d’une conversation sur #django-fr. Carrément plus pratique que la bête page html qui dit ‘en maintenance’, utile à connaître et à avoir dans sa django-boîte à outil.

Les nouveautés de django 1.2 alpha

Avant de commencer à te faire perdre ton temps, je tiens à te prévenir cher lecteur. Si tu as lu la release note de django 1.2 alpha 1, tu n’apprendras rien de plus en lisant ce petit billet.

Pourquoi alors l’écrire ?

Au cas où tu n’aurais pas encore lu la release note et que lire du français t’amuse plus que lire de l’anglais. Et puis comme ça, en plus, tu as le lien vers la release note.

1- Les trucs nouveaux

1.1- protection contre les attaques CSRF.

Les attaques CSRF (Cross-Site Request Foregery) sont rendus  possible par le partage des données de login/session entre les différents onglets d’un navigateur. Du coup, si vous êtes logués sur un site quelconque (prenons facebook comme exemple) et que vous allez sur le site d’un vilain méchant pirate, le vilain méchant pirate pourrait faire des actions sur Facebook, comme si c’était vous qui les faisiez. (Bon pour pouvoir faire cela, il faut que vous cliquiez sur un lien du site du vilain pirate, ou que vous soumettiez un formulaire ou que vous executiez du js).

Django implémente maintenant une façon cool de s’en protéger. (avant il existait un middleware pour le faire). Moralité, si Facebook était en django 1.2, les attaques CSRF ne seraient pas possible.

1.2- Backends des emails

On peut maintenant configurer la façon que django aura d’envoyer des emails. Sympa pour pouvoir debugger et tester les envois d’emails, ça évitera d’avoir à passer par des simulateurs de SMTP.

1.3- Le framework d’envoi de messages

Il remplacera l’ancienne API d’envoi de message et apparemment, il va être juste terrible. Les users authentifiés ou anonyme pourront en envoyer, on pourra les stocket en session ou en cookie, gérer des levels, des tags, que du bon quoi

1.4- Support des multiples bases de données

Alors ça, je l’attendais avec une impatience extrême. On pourra maintenant dire à django de se connecter à X bd différentes, choisir pour chaque requête bd sur quelle base on veut la faire ou où est ce que l’on veut sauver une instance de modèle. Que du bon quoi. Pour ne pas dire de la tuerie

1.5- Un tag if coolos

Là on peut résumer en une phrase : ‘Fini le ifnotequal a b et vive le if a != b’.

Les opérateurs de comparaisons sont enfin supporté. On pourra donc utiliser :

  • ==
  • !=
  • <
  • >
  • <=
  • >=
  • in
  • et and or et not (qui fonctionnaient déjà).

Et en plus, on pourra utiliser des filtres en même temps. Avec un {% if  inst1.var1|bla == inst2.var2|tut %}

Le pied je vous dis.

1.6- Gestion du cache des templates

On pourra configurer un truc de gestion de cache des templates. Et ça, c’est bien.

1.7- Clés en BD

On peut maintenant utiliser les naturals keys dans les fixtures (j’ai pas trouvé de traduction française qui me convenait). Ce qui peut-être bien sympa quand par exemple on a des fixtures qui bossent avec des content types (au hasard hein )

Et on peut maintenant utiliser des int de 64 bits avec le BigIntegerField .

1.8- En vrac

  • une commande en plus sur le runtest qui permet de faire sortir le lanceur de test dés qu’il y a une erreur.
  • Une amélioration de la localisation pour les dates et les nombres qui seront affichés (si l’option est activée) de la façon qui va bien en fonction de la locale.
  • L’ajout de la  propriété readonly_fields pour les champs non éditable (enfin)
  • la possibilité de customiser les couleurs pour les highlight dans la parti admin.

2- Les trucs  obsolètes ou incompatibles

Bon alors déjà, une nouvelle qui va faire que tout le monde va respirer, dans le 1.2 les trucs obsolètes seront encore supportés. Le support n’en sera supprimé que dans la version 1.4.  Ça laisse donc un peu de temps pour organiser ses migrations.

2.1- Le middleware CSRF

Forcément si la protection anti CSRF est refait d’une manière mieux, l’ancienne manière devient obsolète.

2.2- SMTPConnection

Ceux qui utilisaient la classe SMTPConnection pour envoyer des mails devront changer leur code. Heureusement les modifs sont légère (il suffit apparemment de remplacer l’appel au constructeur de la classe par un appel a get_connection () )

2.3- La configuration de la base de données

Forcément ça change. Faudra passer dans la syntaxe multidb, même si on a qu’une seule db.

2.4- L’API d’envoi de message.

Là encore, faut passer à la nouvelle version. Mais ça n’a pas l’air super compliqué. Du replace de nom de fonction et ça devrait le faire.

2.5- Les helpers de formatage de date.

Les fonctions django.utils.translation.get_date_formats() et django.utils.translation.get_partial_date_formats() sont obsolètes et il faudra les remplacer par django.utils.formats.get_format()

2.6- En vrac

  • Du fait des nouvelles fonctionnalités du if, appeler des variable ‘and’, ‘or’ ou ‘not’ est encore moins une bonne idée, vu que vous allez vous manger des TemplateSyntaxError. Bon de toute façon, c’était déjà une très très mauvaise idée d’appeler des variables ‘and’, ‘or’ ou ‘not’, donc …
  • Le LazyObject. Ceux qui utilisaient cette classe non documentée vont devoir modifier leur façon de l’utiliser.
  • Modification de ce que contient le __dict__ dans les instances de Model : Jusqu’à présent le __dict__ ne contenait que les attributs qui correspondaient au champ du modèle. Maintenant il contient un attribut _state qui sert à gérer les db multiple. Ceux qui itere sur le __dict__ de Model devront faire attention à filtrer le _state
  • les fonction get_db_prep_* des Fields ont changé de signature (et il y en a 2 de plus get_db_prep_save et get_prep_lookup )
  • du fait de l’utilisation du cache loader, il faut bien vérifier que les templates tags utilisés sont bien thread-safe (je sais pas pourquoi je sens que ce point là va être le point de départ de dizaines de touffes de cheveux de geeks arrachées).
  • Code de retour du lanceur de test : Le code de retour du lanceur de test ne correspond plus au nombre de test raté. C’est maintenant 0 si aucun test n’a merdé, 1 si il y a eu des merdes.

3- Conclusion

Que du bon dans cette nouvelle version donc. Et en plus pas spécialement beaucoup de modifications à faire pour profiter des nouvelles améliorations. Vivement le 9 mars que la stable sorte quoi. 🙂