Django-easy-maps, c’est comme google maps, mais dans ton site

Cette année se finira comme elle a commencé, en bossant et avec beaucoup moins de temps que ce que j’aimerais en avoir. Il y a pas à dire, il faut vraiment que je me remette à jouer au loto, histoire de pouvoir rêver à un jour, avoir tout le temps que j’aimerais avoir.

Mais ne pas avoir de temps n’est pas une raison pour ne pas perpétuer la tradition des django apps du mois. Surtout que cela fait déjà 16 mois que je tiens, et que tout les mois, qu’il fasse chaud ou froid, que les zombies ou les ET menacent de nous éradiquer ou que le tout derniers MMO à la mode sorte sa béta, je publie un billet de présentation de django app.

Et ce mois ci, je vais vous parler d’une app que j’ai découvert il n’y a que quelques dizaines jours mais qui est bien sympathique (il est même possible que je l’utilise dans un contexte de business).

Cette App c’est donc django-easy-maps.

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

Vous trouverez django-easy-maps sur sa page bitbucket (enfin un projet qui a compris qu’il fallait utiliser mercurial parce que rien n’est mieux que mercurial).
Mais vous aurez aussi le droit à une page pypi (à l’heure ou j’écris, la version sur pypi est la 0.7).

Pour l’installation, vous avez deux méthodes :

  • un petit hg clone ( hg clone https://VOTREUSER@bitbucket.org/kmike/django-easy-maps )
  • un pip ou un easy_install suivant votre préférence.

La doc, elle, tient dans le fichier Readme du projet et dans les commentaires du code. Mais il faut bien avouer que vu la taille de l’app, c’est bien suffisant pour comprendre comment l’utiliser. Si vous voulez comprendre comment elle marche, la par contre, il faudra lire le code.

2- Mais au fait, à quoi ça sert ?

Elle sert à afficher une carte, directement tiré de google maps, qui montre une adresse.

Vous donnez l’adresse que vous voulez voir apparaître à un templatetags et au moment du rendu, vous voyez apparaître un joli composant google maps, avec zoom, déplacage de la carte possible, etc etc. Et en plus, sans avoir besoin d’API Key google ou autre. Plutôt cool nan ?

On peut de plus définir les tailles de la carte, passer un template custom ou utiliser le cache template django.

3- Comment ça marche ?

Tout d’abord il faut penser à installer geopy qui est une dépendance obligatoire. (par pip ou easy_install).

Ensuite, c’est tout simple. On commence par loader le bon templatetags :
{% load easy_maps_tags %}

et ensuite on demande l’affichage de la carte :

{% easy_map “Russia, Ekaterinburg, Mira 32” 300 400 %}

Si on veut personnaliser, on peut, en faisant par exemple :

{% easy_map address 200 200 5 using ‘map.html’ %}

La syntaxe complète du templatetags étant :

{% easy_map < address > [ < width > < height >] [< zoom >] [using < template_name >] %}

Vu mes explications, vous pensez peut-être qu’il n’y a pas de modèles BD. En fait si. L’app stocke en effet la longitude et latitude en BD pour ne pas avoir à les recalculer à chaque fois.

4-Conclusion

Django-easy-maps est une petite app, qui fait pas forcément beaucoup de chose mais qui les fait bien. Et ça j’aime.

Une précision importante, elle fonctionne avec South, donc si vous avez mis en place South pour votre projet django, un simple ./manage.py migrate easy_maps à la place syncdb et ça roule …

5-Conclusion bis

C’est donc avec django-easy-maps que je termine cette année de django-apps du mois. J’espère que certains billets vous ont été utile et vous ont fait découvrir des apps que vous utilisez maintenant quotidiennement.

En tout cas, je vous souhaite un très bon réveillon 2010 et vous dit à l’année prochaine, en espérant que j’aurais le temps de tester l’app que j’ai prévu de vous présenter en janvier qui sera, cette fois-ci, une app d’une toute autre dimension (si j’ai le temps).

Quelques nouveautés de django 1.3

Comme l’indique la roadmap officielle, django 1.3 c’est pour dans bientôt. La bêta avec freeze des fonctionnalités, c’est pour dans 15 jours et la release, pour le 17 janvier. Tout bientôt donc.

Il a de plus déjà été annoncé qu’il n’y aurait pas de nouvelles fonctionnalités dans cette version, que ce serait surtout une release de bugfix et de ‘on finit les choses que l’on a annoncé depuis X années et qu’on a jamais finies’… Enfin, il y a quand même quelque trucs très sympa, voir très très sympa que je vais rapidement lister

Mécanisme de logging

C’est l’un des deux points dont parle la new de la roadmap. A savoir intégrer la lib standard de logging python dans Django. C’est clairement une fonctionnalité sympa, mais il faut avouer que ce n’est pas très très sexy.

Les generics view en mode class based.

Cela permettra à Django de se rapprocher de certains framework web bien connu, avec 2 R dans leur nom (et un O). Et cela devrait aussi simplifier l’utilisation des generics views. De quoi peut-être donner envie à plus de gens de les utiliser. (doc du site officiel)

Choisir le comportement à adopter lors d’un delete d’une FK.

Jusqu’à présent, lorsqu’on supprime un enregistrement en BD et que cet enregistrement était lié à d’autre enregistrement par une FK (par exemple une fonction pour des contacts dans une entreprise), la suppression se faisait en cascade, sans possibilité de modifier cela (à moins d’aller bidouiller un peu profond). Du coup, op vous supprimiez la fonction Secrétaire et c’est toutes vos secrétaires qui passaient à la trappe .. Là, on va enfin pouvoir choisir entre les choix suivant :

  • CASCADE (le fonctionnement actuel)
  • PROTECT (la suppression ne se ferra pas)
  • SET_NULL (la FK sera mise à NULL)
  • SET_DEFAULT (la FK sera mise à la valeur par défaut)
  • SET ()  sera mise à la valeur qui sera passé à SET ( ce pourra être un callable )

Et ça, c’est tout simplement génial !!!  (doc sur site officiel concernant le on_delete des FK)

Préparez un solide alibi, parce que nous savons que vous avez un mobile, un django-mobile

J’ai déjà fait un billet parlant d’une app de monsieur gregmuellegger, à savoir celui sur les websockets. Mais le monsieur étant prolifique, je me vois ‘obligé’ d’écrire à nouveau sur une de ses apps, à savoir django-mobile.

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

Alors on trouve django-mobile à la fois sur :

Pour l’installer donc, un petit coup de

  • easy install ou apparenté
  • git clone

et le tour est joué.

La doc quand a elle, est bien fournie. Avec une description ‘théorique’, des exemples précis et une explication pour chacune des variables de configuration utilisable

2- Mais au fait, à quoi ça sert ?

Comme son nom l’indique, django-mobile permet d’avoir un mode de visualisation mobile pour son site django. Mais en fait, pas seulement. Il permet en fait d’avoir X modes de visualisation pour son site :  mobile, Ipad, sans image, etc ….

3- Comment ça marche ?

Django-mobile fonctionne avec le concept de ‘flavour’.
Vous commencez par définir plusieurs ‘flavour’ pour votre site, tout simplement en les listant dans votre settings.py.

Chaque flavour se défini par son nom et surtout son jeu de template propre qui sont tous rangé dans un ou des sous-répertoires ayant le nom de la flavour en question.

Ensuite il suffit de passer d’une flavour à l’autre. Pour cela deux façon soit c’est une détection automatique (pour passer en mode mobile) soit vos visiteurs peuvent passer d’une flavour à une autre. La valeur de la flavour courante sera alors stockée comme une variable de session (dont le nom est paramétrable)

Le tout fonctionne assez simplement en se basant sur :

  • un middleware qui détecte automatiquement si vous venez d’un terminal mobile ou pas
  • un loader qui rajoute le nom de la flavour en répertoire préfixe pour vos templates
  • deux context processor qui injectent l’un le nom de la flavour courante et l’autre indique si on est en mode mobile ou pas
  • un middleware qui permet de changer la flavour courante.

Django-mobile, en plus d’être simple est pas mal customisable, presque à l’excès. On peut configurer le nom du paramètre de ssion qui stockera la flavour courante choisi par vos visiteurs, le nom du paramètre GET qui permet de changer la flavour courante. On peut également désactiver la possibilité pour l’utilisateur de choisir sa flavour ou choisir si on veut rajouter un répertoire préfix de plus à tout les répertoires de flavour (pour les ranger proprement tous dans un répertoire flavour par exemple).

Que du bon donc, et une petite app à utiliser sans modération (va falloir que je pense à l’intégrer pour histoire de rolistes tiens ). Et puis en plus, j’ai même pu faire un jeu de mot dont je suis excessivement fier dans mon titre de billet…:)

Django-qsstats, parce qu’en vrai,on adore tous faire des stats.

Ce mois-ci, j’aurais pu écrire plusieurs django-app du mois. Si j’avais eu le temps. Mais bon, le jour où j’aurais le temps, ça se saura. Du coup, alors que l’horloge tourne et qu’il ne me reste plus qu’un jour et demi pour écrire ma django app du mois et mon polargeek, j’ai décidé d’écrire ma django-app du mois pour parler de django-qsstats, une petite application comme je les aime.

C’est à dire, qui ne fait qu’une chose, une toute petite chose, mais qui la fait bien. Et qui du coup est facilement intégrable, sans remord.

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

On la trouve sur sa page github. Il me semble bien que le seul moyen d’installation soit à travers github. Mais bon, cloner un repository git hub, ce n’est pas le plus compliqué.

La doc, elle, se limite au fichier Readme et à la lecture des tests. Mais bon, honnêtement, cela suffit.

Par contre attention, en plus de nécessiter django 1.1 à minimal, cette petite app a besoin de python-dateutil (une petite librairie qui ajoute pas mal d’extension plutôt puissante à datetime, si vous ne connaissez pas, je vous recommande vivement d’aller jeter un oeil (mais pas les deux, après vous ne pourrez plus lire la doc … ) )

2- Mais au fait, à quoi ça sert ?

A presque rien, mais c’est bien utile.:) Lorsqu’on veut faire un minimum de stats, de comparaison ou autre, on se retrouve assez vite à vouloir trouver combien il y a eu de nouveaux articles la semaine dernière, combien d’histoires ont été écrites par des rôlistes durant le mois dernier, ou d’utilisateur enregistré les 6 derniers mois…

Faire cela est très simple, un petit queryset puis des petits filters. C’est très simple, mais bon, c’est rapidement chiant, et puis c’est pas très DRY.

Donc on se retrouve assez vite à faire des petits fonctions pour avoir les dates du mois en cours, ou d’un mois précis..

Où alors on se dit que quelqu’un à surement du le faire à notre place, on cherche un peu et on tombe sur django-qsstats.

3- Comment ça marche ?

C’est vraiment tout simple. Il suffit de mettre l’app dans son python-path. Ensuite un peu l’utiliser. Rien à faire de plus. Même pas de syncb vu que c’est une app sans model. (il y a un fichier models mais il n’est là que pour les tests).
Ensuite, ben un exemple sera plus parlant (je reprend l’exemple du site officiel)  :

from django.contrib.auth import User
import qsstats

qs = User.objects.all()
qss = qsstats.QuerySetStats(qs, 'date_joined')

print '%s new accounts today.' % qss.this_day()
print '%s new accounts this month.' % qss.this_month()
print '%s new accounts this year.' % qss.this_year()
print '%s new accounts until now.' % qss.until_now()

Vous le voyez, c’est assez facile. On construit son queryset et ensuite on le passe à qsstats en lui indiquant le champ date qui devra servir au filtrage.

Déjà là, ça serait pas mal. Mais il y a mieux. Il existe la fonction time_series qui permet de récupérer une liste de valeur. Par exemple :

from django.contrib.auth import User
import datetime, qsstats

qs = User.objects.all()
qss = qsstats.QuerySetStats(qs, 'date_joined')

today = datetime.date.today()
seven_days_ago = today - datetime.timedelta(days=7)

time_series = qss.time_series(seven_days_ago, today)
print 'New users in the last 7 days: %s' % [t[1] for t in time_series]

qui donnera :
New users in the last 7 days: [3, 10, 7, 4, 12, 9, 11]

Si cela itère par jour, ce n’est pas magique, c’est parce jour (enfin day) est l’argument step par défaut. Mais on peu bien entendu changer la taille du pas.

Enfin, par défaut, toutes les fonctions utilise Count pour calculer les résultat. (et quand je dis Count, c’est effectivement la class Count des Aggregat de django) Mais on peut changer ce comportement en donnant une valeur au paramètre agregate_class du QuerySetStats.

4-Conclusion

Comme je le disais en introduction, j’aime beaucoup les petites apps qui font des petits trucs, mais qui le font bien. C’est bien souvent plus utile que les grosses apps qui font tout et le café et qui sont bien plus difficile à intégrer (ceci n’est pas une critique de pinax hein, ne me faite pas dire ce que je n’ai pas dit).

Donc j’aime forcément, beaucoup qsstats.

Une petite information un fork de qsstats a été créé, sur bitbucket (et que vous trouverez sur pypi). Il s’appelle django-qsstats-magic. Il rajoute la gestion des heures et des minutes, une optimisation qui fonctionne avec mysql et modifie des trucs en interne. Mais effectivement, je n’ai pas poussé plus loin mes investigations.

Monkey Patching, une petite astuce

Vous connaissez surement cette astuce de dev qu’est le Monkey Patch (voir article wikipedia). En résumé, ça permet d’étendre ou de modifier le code sans modification du code original. Bien entendu, on ne peut monkey patcher que des langages dynamiques.

En python, pour monkey patcher une classe, par exemple, on fait :

class NewKlass :
…..
…..

from project.apps import modtest
modtest.Klass = NewKlass

Rien de bien difficile. Mais compliquons un peu les choses. Imaginons que notre classe Klass soit une classe qui nous convient en partie, mais pas complétement. Certaines fonctions nous conviennent parfaitement, mais pas d’autre. Et pour corser le tout, il faudrait qu’on rajoute des données membres à la classe. On ne peut donc pas ‘juste’ monkey patcher les fonctions qui ne nous plaisent pas…

Comment faire ?

Il faudrait pouvoir dériver de la classe qu’on veut monkey patcher, avant de la monkey patcher.. Mais ce n’est surement pas possible non ? Et ben si. Et c’est très facile.

On commence par écrire notre nouvelle classe :

from project.apps.modtest import Klass as OldKlass

class NewKlass(OldKlass) :
….
….

et ensuite on monkey patch, comme précédemment :

from project.apps import modtest
modtest.Klass = NewKlass

Une précision par contre, lorsque vous allez définir les fonctions dans NewKlass, vous alelz peut être vouloir appeler la fonction mère de la fonction que vous définissez (par exemple dans les models django, on appelle souvent le save de la fonction mère, dans le save de notre fonction)

sauf que là, il faut faire attention si vous faites :

class NewKlass(OldKlass) :
….
….

    def save(self, *args, **kwargs) :
        super( NewKlass,self).save(*args, **kwargs)

vous avez droit à une bonne récursion infinie. Parce que oui, la fonction mère de NewKlass c’est OldKlass, qui est en fait NewKlass, vu qu’on la monkey-patchée.

Il faut donc appeler utiliser la classe grand-mère de NewKlass, en faisant un

class NewKlass(OldKlass) :
….
….

    def save(self, *args, **kwargs) :
        GrandMereNewKlass.save(self,*args, **kwargs)

Petit Rajout : On me demande qui est GrandMereNewKlass. GrandMereNewKlass est en fait MereOldKlass. ou comme le propose @daks_ OldKlass.__base__ (D’ailleurs la question de ‘est ce que ça marche avec de l’héritage multiple qu’il pose dans le même tweet, reste entière 🙂 ).

Bon alors, on sait tous que le monkey Patching, c’est à utiliser avec de grande précaution. Et que bidouiller ainsi en dérivant de la classe que l’on veut monkey patchée c’est tout sauf safe. Mais bon, c’était la question du jeudi de la semaine dernière. ‘Peut-on monkey patcher une classe par une de ses classes filles ?’.

La réponses est donc oui.

Mais ce n’est pas à mettre entre toutes les mains.

Chronique d’un salon réussi

J’en ai parlé (enfin twitté) plusieurs fois. La semaine dernière, nous profitions du salon Solutions pour lancer Crème CRM, le CRM que l’on développe depuis … piou deux ans.

C’était l’occasion d’être, pour la première fois, exposant sur un salon parisien. Pour cette première nous avions prévu les choses en grand :

  • Nouveau kakémono
  • Nouvelle plaquette
  • des clés USB en forme de carte de visite, au couleur de Crème et qui permette de se connecter à une version de démo en ligne
  • de grand tablier blanc, avec un logo Crème, pour continuer l’univers Crème glacée.
  • Une distribution de crème glacée, le 5 octobre, en deux temps. Première partie à la sortie de la conférence de présentation de microsoft Dynamics CRM puis en marchant dans le salon et en arrêtant les visiteurs pour leur offrir une glace et une plaquette, tout en leur expliquant le truc.

Le pari n’était pas forcément gagné d’avance. Le risque était en effet que nous passions pour ridicule, ma chérie et moi, avec nos tabliers (oui la délégation Hybird était redoutablement non discrimante , une femme ma chérie, et un homme moi (je serais presque tentée de dire 1,5 femme en comptant la mini boutchou qui attend tranquillement février pour naitre…) )

Mais au final, le retour fut plutôt bon, je n’ai eu qu’une seule personne qui a refusé de me parler sous prétexte de mon accoutrement.

Le reste du temps, les gens restaient un peu scotchés mais avaient l’air de trouver nos initiatives sympa et de bon goût. Niveau réaction on a tout eu :

  • le mec qui rit aux larme en nous disant que c’était une idée géniale
  • les étudiantes en marketing qui viennent nous dire que c’était terrible
  • une exposante qui me dira ‘je ne pourrais plus manger de glace sans penser à votre CRM’
  • une autre qui trouvera l’idée cool mais compatira tout de même ‘vous devez en vouloir à votre patron qui vous oblige à porter un tablier’
  • des visiteurs (ou des exposants) qui m’arrêteront pour me demander pourquoi je porte un tablier blanc.
  • les gens qui en général hallucinent au départ mais me laissent leur faire mon petit discours, prennent une plaquette et parfois une glace et me donnent leur carte

Au final, et même si il va falloir attendre quelques mois pour pouvoir avoir une réelle idée de l’impact de ce salon, le bilan est positif, un certain nombre de contact,  des retours plutôt bon sur le design, l’ergonomie et les fonctionnalités de Crème.

Petit intermède Caliméro

Et pourtant, ce ne fut pas facile. A croire que tout c’était ligué contre nous.

Nous avions raté à 30 secondes (30 put…. de secondes), notre TGV, ce qui nous a obligé à en prendre un autre (en payant une surtaxe) et à arriver encore plus tard que prévu sur Paris. (Ce qui nous a permis de marcher à travers la Défense et Courbevoie, en pleine nuit, pour trouver notre hôtel… Mais bon, c’est sympa la Défense à minuit).

Arrivés (enfin) à l’hotel, je me rend compte que j’ai oublié de prendre des chaussures correctes et que je n’ai que mes baskets (autant dire que costume / basquettes, ça ne le fait pas) ce qui m’obligera à aller en acheter le matin même du salon et conséquence encore pire, à faire 2 jours de salons dans des chaussures complétement neuves ….

D’ailleurs le retour ne fut pas mieux …

Tout d’abord serrés comme des sardines pour faire la défense -> la gare de lyon..

Puis déçus parce que les billets IdTGV on ne peut les échanger que 5h avant le départ… 5h… mais qui a envie de changer ses billets 5h avant le départ ? 2h30 avant le départ comme nous oui… mais 5h30. Donc bingo, 2h30 d’attente.

Ensuite dans le wagon idTGV Zen, le plus bruyant du monde, avec une bande de trentenaire qui foutaient le bordel en buvant des petites cannettes de 1664 … (non mais sérieux là …) Et pour finir 20 minutes d’attente pour avoir le droit de monter dans un ficht.. de taxi.

Fin du Petit intermède Caliméro

Pour clôturer ce billet, et histoire que ce ne soit pas qu’un billet ‘récit of my life’, je vais essayer de vous donner un conseil.

Si vous devez lancer un produit, être exposant sur un salon, n’hésitez pas à être décalé, différent. N’hésitez pas à prendre des risques, si vous trouvez une bonne idée, qui reste dans le ton, qui peut être relié facilement à votre produit, qui est sympa sans être ridicule, fun sans être débile, vous marquerez les gens et ils se souviendront de vous. Et qu’ils se rappellent votre nom, c’est la première étape pour que vous puissiez leur vendre quelque chose. [ Et je sais que quand je les relancerais par mail, ils vont tout de suite me remettre, et que si ils se rappellent de moi, c’est un plus, un gros plus ]

Alors effectivement, c’est bien plus difficile de passer deux jours habillé avec un tablier blanc que de rester, comme tout les autres autour,  en costard / cravate. Mais je pense que ça vaut le coup.

Le plus difficile reste le dosage. Savoir rester du bon coté de la ligne jaune, du coté de l’idée géniale et ne pas, à trop vouloir en faire, passer du coté de l’idée ridicule.

Pour finir, (parce que demain j’ai un autre salon et que je ne suis pas tout a fait prés) j’aimerais parler d’une autre initiative ‘décalée’ du même style. Celle de Pliciweb et de leur produit clic and cash qui consiste tout bêtement (ou tout génialement) à vendre des sites web en conserves (oui en conserves, dans des boites de conserves). Leur idée est tout simplement géniale. Donc voilà, j’avais juste envie d’en parler. 🙂

Turpial, encore un nouveau client twitter.

Turpial est un client twitter, développé en python et en GPL v3,  que j’ai découvert récemment grâce à http://ubunlog.com Comme j’aime bien tester tout les clients twitter que je découvre, je l’ai installé pour voir ce qu’il avait dans le ventre.

Au niveau de l’installation, deux manières de faire :
soit en ajoutant le ppa qui va bien, si vous avez une ubuntu en faisant :

  • sudo add-apt-repository ppa:effie-jayx/turpial-devel
  • sudo apt-get update
  • sudo apt-get install turpial

soit en récupérant les sources sur sa page github et en faisant un petit python setup.py install

Mais qu’à donc de spécial ce petit client :

  • déjà il est dev en python
  • ensuite il gère twitter mais aussi identi.ca
  • Il possède un mode 1 colonne et un mode 3 colonnes, chaque colonne pouvant alors des intervalles de rafraichissement différents
  • Il permet de gérer les listes comme étant une TL a part et c’est bien le premier clients que je vois faire ça.

Ce qu’il lui manque :

  • pouvoir être multi compte
  • avoir une gestion du lu / non lu
  • pouvoir configurer le nombre de colonnes que l’on souhaite (je révérais d’un client qui me permette d’avoir ma TL plus une TL par liste… le pied … )

Mais je dois avouer que j’ai été plus qu’agréablement surpris par l’essai de Turpial. Je vais du coup suivre son développement pour voir ce que vont amener les prochaines versions.

Et en attendant, quelques petites images du client (récupérées directement du site officiel).

Django-taggit, le tag est mort, vive le tag ..

J’ai déjà fait, il y en fait 11 mois, un billet de la django app du mois sur une app de tag, django-tagging. Lorsque je l’ai testé, django-tagging était à la version 0.3. Aujourd’hui, elle est version 0.3.1. Et les derniers commit remonte à janvier 2010 ( ce sont ceux ayant aboutis à la version 0.3.1)

Je me suis donc dit, qu’il était peut-être tant de revenir sur le sujet et de présenter une autre app django, sur le même sujet, qui même si pour l’instant présente quelques lacunes comparée à django-tagging, me semble prometteuse.

Et cette app, c’est, roulement de tambour…., django-taggit d’Alex Gaynor (un trublion bien connu pour ceux qui font du django)

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

Alors on le trouve tout simplement sur sa page Pypi ou sur sa page github d’ailleurs

Pour l’installation rien de plus simple :

  • un easy_install ou un pip
  • un git clone

Pour la doc, là il n’y a vraiment rien à redire, le projet offre une doc très bien fournie sur readthedocs.org.

2- Mais au fait, à quoi ça sert ?

Tout simplement à taguer des objets. Exactement comme django-tagging donc. Vous allez pouvoir taguer vos objets, filtrer les objets en fonction des tags qu’ils ont ou trouver des objets similaires de par leur tag.

Vous allez aussi pouvoir modifier légèrement la mécanique interne. Par exemple si utiliser des generics key ne vous plait pas, tout est prévu pour que vous puissiez simplement les remplacer par des foreign key. Vous pourrez aussi changer d’autre mécanismes comme le model utilisé pour sauver les Tags.

3- Comment ça marche ?

Tout d’abord il faudra que vous ajoutiez, pour chaque models que vous voulez rendre ‘tagable’ un manager de tag. (Pour ceux qui se souviennent django-tagging permet de taguer directement des instances de models, sans modifier la classe Model en question).

Ca peut paraître un peu lourd et ça rend l’app assz intrusive, mais bon, c’est comme ça. Et puis du coup ça permet, il faut bien l’avouer d’avoir une écriture plus fluide et plus ramassé de son code. Nul besoin de toujours passer par la classe Tag en filtrant sur l’objet dont l’on veut récupérer les tags. Un simple object.tags suffit pour avoir tout ses tags.

Facilité d’utilisation ou intrusivité, à vous de choisir, django-taggit, lui  à choisit. (Et bon, au pire, un bon petit contribute_to_model devrait permettre une extensibilité moins intrusive).

Pour ajouter les tags, les syntaxes possible sont à peu près les mêmes que celle de django-tagging, à savoir (l’image est une capture d’écran d’une partie de la doc) :

Un truc à ne pas oublier, django-taggit utilise des many to many. Donc, n’oubliez pas le save_m2m si vous utilisez des forms.

Ensuite, vous pourrez bien entendu supprimer des tags, les lister, filtrer des objets en fonction de leur tags ou avoir une liste des objets similaires. C’est une vrai liste qui est classée par ordre de similarités.

4- Une app peut en cacher deux autres.

Là, à cette instant de votre lecture vous vous dites peut-être ‘Mais mer..mince alors, il manque des trucs comparés à django-tagging, il n’y a même pas de templates tags d’affichage’.

Et vous auriez raison. Sauf que, sauf que… Il y a des applications qui étendent django-taggit à savoir :

5- Au final

Vu le statut de quasi moribond de django-tagging comparé à la vigueur actuelle de django-taggit, je pense vraiment que si vous avez besoin d’une application qui gére les tags, django-taggit est un meilleur choix. Et puis, je trouve ça rassurant qu’il y ait des applications externes pour étendre django-taggit.

Django Simple Captcha et tout devient si simple

Comme d’habitude le mois d’aout fut une vraie folie. Et qui dit mois de folie dit, billet qui prennent du retard. Heureusement que j’ai pu tricher en publiant la première interview. (ben oui c’est beaucoup plus rapide de poser des questions que d’y répondre, enfin beaucoup plus rapide d’écrire les questions dans un mails quoi).

Du coup, je suis presque en retard pour la django app du mois. Et pour ne pas être en retard, j’ai choisi pour ce mois ci, une django app simple, mais très utile, django simple captcha (pour la petite histoire j’ai découverte cette app en testant django-tellafriend, une application dont il faudra que je vous parle également).

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

Alors on le trouve, tout simplement, sur la page google code qui lui est consacré. Pour l’installation,   c’est comme toujours du classique (ha ce que j’aimerais un jour, avoir une surprise à ce niveau là, pouvoir gouter à un peu de nouveauté… mais non, c’est toujours pareil.

Vous avez donc le choix entre :

  • easy_install
  • un tar.gz de la dernière release
  • un checkout de SVN

Dans tout les cas, il vous suffira une fois votre petite application installée, de la rajouter dans les INSTALLED_APP, de lancer un petit syncdb et magie… ça fonctionnera.

Enfin, si vous avez pensé à installer PIL, bien entendu.

La doc elle, est minimaliste mais plutôt claire et bien faite.

2- Mais au fait, à quoi ça sert ?

He ben mon cher ami, c’est indiqué dans le titre. C’est une application de captcha. Elle permet dans sa version de base de proposer trois méthodes de tests de l’utilisateur :
le très classique lettre dans le désordre
l’opération mathématique (toi aussi répond à 4+2)
le choix d’un mot, au hasard, dans un dictionnaire.

Et là, ou c’est vraiment le top avec cette petite app, c’est que si vous avez installé Flite, vous pourrez même avoir votre captcha en Text-so-speech, et vive l’accessibilité !!

3- Comment ça marche ?

En fait rien de plus simple, l’app fourni tout simplement un noueau type de Field a utiliser dans un formulaire.

Et oui, rien de plus simple.

On crée son formulaire, on rajouter un champ Captcha et quand le formulaire a été posté, on fait un joli is_valid() pour savoir si c’est bon.
Et au niveau de la configuration, les possibilités sont très complètes. On peut configurer le taux de bruit appliqué à l’image, les inclinaisons maximums appliqués aux lettres et aux chiffres, la font à utiliser ainsi que sa taille, les différentes couleurs, etc etc,

4- Mais encore

Ce qui est de bien avec cette app, c’est qu’en plus de penser à tout ce qui accessibilité, elle est bien pensé. Elle vous permet en effet de rajouter vos propres générateurs de tests. Il suffit de coder une petite fonction qui renverra un tuple contenant la question et sa réponse dans un tuple. Et le tour est joué.

Et ça c’est plutôt très sympa.

Dernière précision, la page google code contient un bouton flattr, si vous avez un compte flattr (cet excellent nouveau système de rétribution dont il faudra que je parle un jour, mais google est votre ami), n’hésitez pas à cliquer sur le bouton.

Petit tour du coté des itertools, billet sans nucléaire dedans, promis

Le module itertools est un module bien pratique auquel on ne pense pas assez souvent. En tout cas auquel, moi, je ne pense pas assez souvent. Et pourtant, il peut grandement simplifier pas mal de ligne de code, dans un bon nombre de situation. Il faut juste savoir que les fonctions qu’il propose existe.

Ce billet a donc 2 objectifs, vous faire découvrir les itertools (je ne vais pas lister toutes les fonctions juste celles dont je devrais me servir plus souvent et que j’oublie) et me permettre de ne pas oublier que je pourrais les utiliser.

Point important : Un certain nombre des itertools permettent de gérer les iterateur infinis, ce que ne permettent pas les fonctions ‘normales’ comme map par exemple (qui renvoie une sortie complétement calculée, ce qui est par définition impossible avec un iterateur infini).

Précision : les exemples de code sont ceux fournis par la doc officielle des itertools

itertools.chain (*iterables)

permet d’avoir un iterateur qui retourne tout les éléments du premier iterable passé en paramètre, puis du second, puis du troisième, etc etc… Bien pratique pour aérer son code.

def chain(*iterables):
# chain('ABC', 'DEF') --> A B C D E F
for it in iterables:
for element in it:
yield element

Depuis python 2.6, il existe une classmethod de chain, from_iterable(iterable) qui ne prend qu’un argument, un iterable contenant tout les iterables.

@classmethod
def from_iterable(iterables):
# chain.from_iterable(['ABC', 'DEF']) --> A B C D E F
for it in iterables:
for element in it:
yield element

itertools.compress(data, selectors)

compress n’est disponible qu’en python 2.7. Cette fonction retourne un iterateur contenant que uniquement les valeurs de data auxquelles correspondent un élément évalué à True dans le selectors. Compress s’arrête dès que data ou selectors est vide.

def compress(data, selectors):
# compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F
return (d for d, s in izip(data, selectors) if s)

itertools.count(start=0, step=1)

Cette fonction bien que présente depuis longtemps a droit à quelques modifications dans python 2.7. Count gagne en effet l’argument step et la possibilité d’itérer sur des arguments non integer.

def count(start=0, step=1):
# count(10) --> 10 11 12 13 14 ...
# count(2.5, 0.5) -> 3.5 3.0 4.5 ...
n = start
while True:
yield n
n += step

itertools.dropwhile(predicate, iterable)

Construit un iterateur qui ne renvoie aucun élément de l’iterable tant que le prédicat est vrai, ensuite, tout les éléments de l’iterable sont renvoyés

def dropwhile(predicate, iterable):
# dropwhile(lambda x: x<5, [1,4,6,4,1]) --> 6 4 1
iterable = iter(iterable)
for x in iterable:
if not predicate(x):
yield x
break
for x in iterable:
yield x

itertools.takewhile(predicate, iterable)

Construit un iterateur qui, tant que le prédicat est vrai, renvoie les éléments de l’iterable.

def takewhile(predicate, iterable):
# takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4
for x in iterable:
if predicate(x):
yield x
else:
break

itertools.ifilter(predicate, iterable) et itertools.ifilterfalse(predicate, iterable)

Construit un iterateur qui ne renvoie que les éléments pour lesquels le prédicat est respectivement True ou False. Si predicate est à None, l’iterateur renvoie les éléments respectivement True ou False.

def ifilter(predicate, iterable):
# ifilter(lambda x: x%2, range(10)) --> 1 3 5 7 9
if predicate is None:
predicate = bool
for x in iterable:
if predicate(x):
yield x

itertools.imap(function, *iterables)

Renvoie un iterateur qui applique function en utilisant les iterables comme argument. Si function est None, les arguments sont retournés sous la forme d’un tuple. Imap s’arrête lorsqu’elle atteint la fin du plus petit des iterables. Imap est utile lorsque l’on utilise des iterateur infinie qui provoque une erreur avec map.

def imap(function, *iterables):
# imap(pow, (2,3,10), (5,2,3)) --> 32 9 1000
iterables = map(iter, iterables)
while True:
args = [next(it) for it in iterables]
if function is None:
yield tuple(args)
else:
yield function(*args)

les autres i-versions des fonctions classiques.

Comme l’on trouve imap, il existe aussi izip, izip_longest et islice,

Parmi les autres fonctions il y a des fonctions de combinaisons, de calcul, de cycle, de groupby, mais celles là, vous les trouverez sur la doc officielle.

Django-websocket parce que sans chaussettes, le web, il pue un peu des pieds

Et oui, malgré la chaleur, malgré les vacances, la plage et l’appel de starcraft 2, malgré tout cela, je reste fidèle au poste et je publie une django app du mois. Bon ok, c’est le dernier jour du mois, mais je suis encore dans les clous.

Mais par contre, vu que c’est l’été, les vacances, je vais pour une fois parler d’une app qui est pour faire tout sauf de la prod. C’est une app toute jeune et qui en plus s’aventure dans un domaine encore très peu supportés dans les navigateurs (pour l’instant uniquement dans Chrome 4, Firefox 4 et Safari 5) , celui des websockets. C’est quoi une websocket vous allez me dire ? C’est un mécanisme qui apparaît dans HTML 5 et qui permet d’avoir un mécanisme de connexion persistante et bi directionnelle entre le serveur web et le browser de l’utilisateur. Trop cool vous allez me dire. Je ne puis qu’être d’accord avec vous. (pour plus d’infos sur les websockets vous pouvez aller lire la page wikipedia ou la norme W3C qui est plutôt facile à lire).

Django-websocket est donc une toute récente app (version 0,3 à l’heure ou j’écris ce billet) qui permet de commencer à s’amuser avec ces adorables websockets.

1- Où on le trouve, comment on l’installe, la doc.

Vous trouverez django-websocket sur sa page pypi ou sur sa page github. L’installation se fera donc soit :

  • avec easy_install
  • un git clone

Comme le code évolue pas mal et que de toute façon c’est pour l’instant plus une app pour tester et pas pour mettre en prod, moi, je vous conseillerais le git clone qui vous permettra d’avoir plus souvent une app à jour.

La documentation est plutôt bien fournie, claire et suffit pour démarrer. Le repository github permet d’avoir en plus les tests et une petite application example de echo.

2- Comment ça marche ?

En fait c’est vraiment super facile, il suffit d’utiliser deux décorateurs de vues soit :

  • require_websocket pour obliger la vue à fonctionner en websocket
  • accept_websocket si l’on veut permettre à la vue de fonctionner sans les websockets.

Ensuite il n’y a qu’un seul objet à utiliser request.websocket sur lequelle on pourra :

  • faire des attentes et récupérer un message quand il y en a un (wait)
  • vérifier si il y a des messages ( has_messages )
  • lire un message ( read )
  • envoyer un message ( send )
  • les utiliser comme un iterator (ce qui ferrait comme un wait dans une boucle avec la gestion en plus de la fermeture de la socket )

Petite précision, le serveur de développement de django n’est pas multithread, il n’est donc pas possible d’ouvrir deux requêtes concurrentes avec. L’app fourni donc une commande spéciale pour le runserver ( –multithreaded ) qui permet de contourner le problème.

3- Un petit Mad Exemple

Histoire de m’amuser un peu avec l’app, j’ai commis un petit exemple avec, en me basant sur le echo exemple. Mon exemple est tout con, vous entrez une chaine de caractère et je lance (grâce à restkit) une recherche google toute les 30 secondes sur la chaine de caractère. Les dix premiers résultats de la recherche sont ensuite affichés grâce à la websocket.

Vous pourrez trouver le code en question sur le tout nouveau repository bitbucket que j’ai du coup, crée pour l’occasion.

Django-improved-inlines, enrichissez facilement vos contenus et ça, sans payer l’ISF

La pluie ayant décidé d’être l’invité surprise du week-end, j’ai donc une bonne excuse pour ne pas aller prendre des coups de soleil à la plage mais rester bien tranquillement sur mon clavier. Autant donc en profiter pour vous parler de l’application django du mois, j’ai nommé django-improved-inlines. Oui, je sais, elle a un nom à rallonge. Django-improved-inlines est en fait une version légèrement dopé de django-inlines (d’où le improved) qui fait elle même parti du package django-basic-apps. Oui je sais, ça commence à faire un arbre généalogique digne d’une série américaine (ou du trône de fer).

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

Vous le trouverez sur sa page github. C’est d’ailleurs là que vous pourrez apprendre que cette sympathique petite app est une version modifiée de l’app inlines de django-basic-apps.

Pour l’installation deux méthodes :
directement en clonant le repository git de github
avec un petit easy_install bien de chez nous.

Attention, l’application pour fonctionner à besoin de BeautifulSoup mais l’installation par easy_install ne vous l’installera pas automatiquement. Un petit easy_install beautifulsoup sera donc de rigueur. Et oui.

Quand à la doc, elle tient dans un mouchoir de poche, à savoir le fichier readme mais au vu de la simplicité de l’app, ce n’est pas vraiment dérangeant.

2- Mais au fait, à quoi ça sert ?

En fait c’est tout simple. Cela vous permet, lorsque vous rédigez des contenus, d’insérer à l’intérieur d’autre contenu gérer par votre django. Et en les mettant en forme avec des templates spécifiques.

Imaginons par exemple que vous voulez insérez des images d’une manière simple dans un billet de blog, ou des blocks de texte ou ce que vous voulez en fait. Et cela, sans modifier le template de votre contenu principal. Et oui. Mais non, ce n’est pas de la magie.

3- Comment ça marche ?

En fait, cela marche en deux temps. Tout d’abord dans le template d’affichage de votre contenu principal, il faut déclarer et utiliser le template de django-improved-inlines, comme ceci :

{% load inlines %}
…....
{{ post.body|render_inlines }}

Ensuite, tout va se jouer dans votre contenu, ici le body de votre post. Vous allez parsemer celui si de bouts d’xml qui seront process par BeautifulSoup et Improved-Inlines et qui seront transformés en html (grâce à un template).

L’exemple le plus simple est :

<inline type="media.photo" id="1" />

qui affichera l’objet de pk 1 qui est modélisé par la classe photo contenu dans l’app media.

Mais vous pourrez également utiliser les attributs xml suivant :
ids pour afficher plusieurs id, séparées par des virgules.
filter pour passer un filtre django
template pour choisir le template django qui sera utilisé (par défault l’app utilise inlines/app_model.html)
class qui permet de passer une class au template

ce qui donnerait :

<inline type="calendar.event" filter="date__gte=datetime.date.today()" template="calendar/event_inline.html" />

ou encore :

<inline type="app.model" id="<some pk>"/> <inline type="app.model" ids="<some pk>,<some other pk>" />

4-Conclusion

Je n’ai pas encore eu l’occasion de m’amuser, ‘pour de vrai’ avec cette appli toute simple, ce n’est pas l’envie qui m’en manque parce que je pense lui trouver une foule d’application qui me faciliteront grandement la vie.
J’ai une seule petite appréhension que le process par BeautifulSoup ne ralentisse pas quelque peu le rendering des pages. Ca serait d’ailleurs un ralentissement à évaluer. En tout cas, amusez vous bien avec cette appli aussi simple, qu’utile.