Le petit coin de Nicolas

Aller au contenu | Aller au menu | Aller à la recherche

Python - Django

Construire votre atelier logiciel python - Suite : Mercurial

Ce billet va être orienté sur le gestionnaire décentralisé de source mercurial (aka hg). Dans le précédent billet, nous avions juste installé le logiciel Mercurial. Il est temps de le paramétrer.

Paramétrage de base

Créons un dépot mercurial de zéro :

workon <envt>
cd Projets/Python
hg init testhg

Le contenu de ce dossier est vide à l'exception d'un dossier .hg qui contient tout votre historique et configuration de votre dépôt mercurial (les utilisateurs de svn seront un peu déboussolés car ils ne trouveront pas d'équivalent aux répertoires .svn un peu partout dans l'arborescence du projet ;-) )

Créer le fichier .hg/hgrc (si vous avez cloné un dépôt, celui-ci existe déjà avec la référence du dépôt cloné pour d'éventuelles interactions futures) et vous pouvez y ajouter plein de choses dont notamment :

  • Des paths qui vous permettent de définir facilement où sont le(s) dépôts mercurial de votre projet. Dans mon cas, "default" est sur mon serveur privé et "bitbucket" correspond à l'espace projet sur Bitbucket. La commande hg push enverra par défaut sur le dépôt "default". Si je veux pousser sur mon dépôt bitbucket, il me faudra saisir hg push bitbucket. C'est toujours plus sympa à taper que l'url complète du dépot à chaque push.
  • Un "username" qui fait que vous pouvez spécifier un compte pour vos commits ; sinon mercurial prend votre login système comme référence.
[paths]
default = ssh://login@server.com/hg/project/
bitbucket = ssh://hg@bitbucket.org/login/project/

[ui]
username = login

C'est le minimum syndical pour un dépôt mercurial à mon sens. Il existe plein d'autres options pour le fichier hgrc, ainsi que la liste des extensions de mercurial

Premières intéractions avec mercurial

Pour ajouter un fichier :

echo "Test Mercurial" > README
hg st # pour hg status
? README
hg add README # pour ajouter le fichier README dans le référentiel

Pour ajouter un ensemble de fichier (marche aussi avec une sous-arborescence)

for i in 1 2 3; do echo "Test Mercurial $i" > README-$i; done
hg st # on voit que le fichier README est bien ajouté et que les autres sont inconnus du référentiel
A README
? README-1
? README-2
? README-3
hg add # si pas de fichier précisé, on ajoute tous les fichiers inconnus du référentiel
adding README-1
adding README-2
adding README-3

Pour commiter les fichiers dans le référentiel :

hg commit -m "Import Test"

Pour contrôler le dernier commit :

hg tip
changeset:   0:830fddaa0d2f
tag:         tip
user:        login
date:        Mon Jul 19 22:49:50 2010 +0200
summary:     Import Test

Publier en une fois sur plusieurs dépôts

Les hg push && hg push bitbucket, cela va un moment. Il faudrait trouver un moyen plus sympa de publier en une fois sur tous les dépôts référencés. Pour cela, l'extension publishall est votre amie.

Une fois le fichier publishall.py récupéré, il suffit d'enrichir votre fichier .hg/hgrc de la façon suivante :

[paths]
default = ssh://login@server.com/hg/project/
bitbucket = ssh://hg@bitbucket.org/login/project/

[ui]
username = login

[extensions]
publishall = /path/to/extensions/hg-publishall/publishall.py

Au prochain commit, il vous suffira de faire un hg pusha pour publier sur l'ensemble de vos dépôts.

Installation de hg-git

Si vous voulez travailler avec github tout en conservant mercurial, c'est possible :

easy_install hg-git # Cela ne semble pas fonctionner à ce jour avec pip...

Dans le fichier .hg/hgrc de votre projet :

[paths]
default = ssh://login@server.com/hg/project/
bitbucket = ssh://hg@bitbucket.org/login/project/
github = git+ssh://git@github.com/login/project

[ui]
username = login

[extensions]
hgext.bookmarks =
hggit =
publishall = /path/to/extensions/hg-publishall/publishall.py

[git]
intree = True

Ensuite, après avoir créé bien sur votre projet sur github :

hg push github

Et votre code est alors disponible sur Github.

Publier son propre code via hgweb

Voir le tutoriel "Installer l’interface web de consultation d’un dépot mercurial" ;-)

D'autres choses à partager sur Mercurial ?

Créer son atelier de développement logiciel Python

Aide mémoire pour la confection d'un atelier logiciel autour de Python. Il sera complété au fur et à mesure...

Pré-requis :

  • pip ; un sudo easy_install pip doit fonctionner si setuptools est installé.

Installation de Virtualenv & Virtualenvwrapper

Virtualenv permet de créer des environnements virtuels python avec les librairies de votre choix. Vous pouvez avoir un environnement virtuel pour chaque version de DJango (dj-096, dj-100, dj-110, dj-120, etc) et contre lesquels vous allez pouvoir tester l'application que vous développez. L'autre avantage est que l'on peut installer ce que l'on veut comme librairie python, sans avoir de droit système. De mémoire, on doit même pouvoir utiliser plusieurs versions de python si besoin. Bref, l'idéal pour des tests et ne pas pourrir son système global :-)

Virtualenvwrapper est l'outil pour les fainéants qui utilisent virtualenv puisqu'il simplifie l'utilisation de virtualenv. Il y a des options assez sioux ; se reporter à la documentation

sudo pip install virtualenv virtualenvwrapper

Dans votre fichier $HOME/.bashrc :

# Création du répertoire accueillant les environnements virtuels
export WORKON_HOME=$HOME/python/virtualenv
# Instructions spécifiques pour l'usage de PIP
export PIP_VIRTUALENV_BASE=$WORKON_HOME
export PIP_RESPECT_VIRTUALENV=true
# Chargement des commandes fournies par virtualenvwrapper 
. /usr/bin/virtualenvwrapper.sh

Ensuite dans votre console :

# Création du répertoire accueillant les environnements virtuels
mkdir -p $HOME/python/virtualenv
# Prise en compte des modifications réalisées précédemments
source $HOME/.bashrc

avec pour résultat :

virtualenvwrapper.user_scripts Creating /home/nsteinmetz/python/virtualenv/initialize
virtualenvwrapper.user_scripts Creating /home/nsteinmetz/python/virtualenv/premkvirtualenv
virtualenvwrapper.user_scripts Creating /home/nsteinmetz/python/virtualenv/postmkvirtualenv
virtualenvwrapper.user_scripts Creating /home/nsteinmetz/python/virtualenv/prermvirtualenv
virtualenvwrapper.user_scripts Creating /home/nsteinmetz/python/virtualenv/postrmvirtualenv
virtualenvwrapper.user_scripts Creating /home/nsteinmetz/python/virtualenv/predeactivate
virtualenvwrapper.user_scripts Creating /home/nsteinmetz/python/virtualenv/postdeactivate
virtualenvwrapper.user_scripts Creating /home/nsteinmetz/python/virtualenv/preactivate
virtualenvwrapper.user_scripts Creating /home/nsteinmetz/python/virtualenv/postactivate

Création de son premier environnement virtuel

mkvirtualenv demo
New python executable in demo/bin/python
Installing setuptools............done.
virtualenvwrapper.user_scripts Creating /home/nsteinmetz/python/virtualenv/demo/bin/predeactivate
virtualenvwrapper.user_scripts Creating /home/nsteinmetz/python/virtualenv/demo/bin/postdeactivate
virtualenvwrapper.user_scripts Creating /home/nsteinmetz/python/virtualenv/demo/bin/preactivate
virtualenvwrapper.user_scripts Creating /home/nsteinmetz/python/virtualenv/demo/bin/postactivate

Sur votre prompt, vous devez voir un petit (demo) apparaître indiquant que vous utilisez cet environnement :

Avant :

[nsteinmetz@citrouille ~]$

Après :

(demo)[nsteinmetz@citrouille ~]$ 

Comme tout projet doit avoir sa documentation et être versionné, installons sphinx et mercurial.

pip install sphinx mercurial

Il ne vous reste plus qu'à installer les autres librairies dont vous avez besoin.

Pour sortir de votre environnement, il suffit d'utiliser la commande deactivate.

Pour revenir dans votre environnement, il faut utiliser la commande workon :

  • Si vous n'avez qu'un environnement virtuel (comme dans notre cas) alors vous basculez automatiquement dans cet environnement
  • Si vous avez plusieurs environnements virtuels, alors workon liste les environnements disponibles. Pour en activer un en particulier, il faut préciser son nom ; dans notre cas workon demo.

To be continued... et je suis preneur de vos retours / idées / ...

mod_wsgi 2.6 pour slackware 13.0 x86_64 et 12.x

Décidément, je vais finir par packager mod_wsgi pour toutes les distributions : après Arch il y a de ça quelques temps, voici le package Slackware.

Restons modeste, il ne s'agit que d'une mise à jour mineure du slackbuild existant pour passer de la version 2.0 à 2.6.

Une fois récupéré :

 bash
installpkg mod_wsgi-2.6-x86_64-1_nst.tgz

Ensuite dans /etc/httpd.conf, il vous suffit de rajouter une ligne du type :

 apache
Include /etc/httpd/mod_wsgi.conf

Puis de redémarrer apache :

 bash
/etc/rc.d/rc.httpd reload

Pour Slackware 12.2 :

Par contre, il vous faut créer le fichier /etc/httpd/mod_wsgi.conf :

 apache
LoadModule wsgi_module lib/httpd/modules/mod_wsgi.so

Django : limit_choices_to pour présenter un sous-ensemble des données d'un modèle

Dans le cadre des relations "One to many" ou "Many to Many", il est possible de présenter un sous-ensemble de votre modèle en fonction de critères de tri.

Codant une application de gestion de reverse proxys pour les sites web Vélos en libre service, il me faut gérer différents types d'url (une url publique, une url pour les abonnements, une url d'admin, les déclinaisons linguistiques et autres alias en tous genre) et ce pour chaque type d'environnement (VABF, PREPROD, PROD). J'aurais pu créer autant de modèles que j'ai de type d'url mais cela aurait été particulièrement contre-productif. J'ai donc un modèle unique avec les paramètres "type d'url" et "environnement". Dès lors, quand je définis les urls d'une ville, il me suffit de faire des relations "One to Many" ou "Many to many" vers mon objet Url.

Cela donne grosso modo la chose suivante pour l'objet Url:

 python
class Url(models.Model):
    """
    Url description
    """
    ENVT_CHOICES = (
        ('1', 'VABF'),
        ('2', 'PREPROD'),
        ('3', 'PROD'),
    )
    URL_CHOICES = (
        ('1', 'www'),
        ('2', 'subscription'),
        ('3', 'admin'),
        ('4', 'secondary'),
        ('5', 'translation'),        
    )
    name = models.CharField("DNS", help_text="Provide url of the site without http(s)://", max_length=100)
    description = models.CharField(help_text="You can provide extra information on the url", blank=True, max_length=100)
    url = models.URLField("URL", help_text="Provide url of the site *with* http(s)://", verify_exists=False)
    urltype = models.CharField("URL Type", help_text="What kind of url it is ?", max_length=20, choices=URL_CHOICES)
    envt = models.CharField("Environement", help_text="In which environment is used this url ?", max_length=100, choices=ENVT_CHOICES)
    
    def __unicode__(self):
        return self.name

Dans un premier temps, la classe Town est assez simple à monter :

 python
class Town(models.Model):
    """
    Town
    """
    ENVT_CHOICES = (
        ('1', 'VABF'),
        ('2', 'PREPROD'),
        ('3', 'PROD'),
    )
    STATE_CHOICES = (
        ('1', 'On construction'),
        ('2', 'On maintenance'),
        ('3', 'Open'),
        ('4', 'Closed'),
    )
    name = models.CharField(help_text="Provide the name of the town", max_length=100)
    description = models.CharField(help_text="You can provide extra information on the town", blank=True, max_length=100)
    prod_status = models.CharField("PROD status", help_text="State of the site on PROD environment", max_length=20, choices=STATE_CHOICES)
    prod_www = models.ForeignKey(Url, verbose_name="WWW Public URL", help_text="Public url of the site like www.velib.paris.fr", related_name="prod_www")
    prod_abo = models.ForeignKey(Url, verbose_name="Subscription URL", help_text="HTTPS URL used for all sensible process like subscribption, my account, etc. Is often like https://abo-<town>.cyclocity.fr", related_name="prod_abo",)
    prod_admin = models.ManyToManyField(Url, verbose_name="Internal administration URL(s)", help_text="URL used to access back-office", related_name="prod_admin") 
    prod_other = models.ManyToManyField(Url, verbose_name="Other URL(s)", help_text="Other urls related to the site like aliases related to the public url", related_name="prod_other", blank=True)
    prod_translation = models.ManyToManyField(Url, verbose_name="Translations URL", help_text="If site has translated versions, their public urls are listed here" ,related_name="prod_translation", blank=True)    

Cette modélisation, bien que remplissant le besoin a un désavantage certain : tous les objets de type Url sont présentés. Si on part sur 17 villes * 3 environnements * 3 urls "publiques" à minima, soit pas moins de 153 urls disponibles. Pas simple de s'y retrouver (et encore je vous dis pas tout, il y en a bien plus en fait ;-) )

Il faut alors être en mesure pour l'attribut prod_www de ne présenter que les urls de type "www" et pour l'environnement "prod".

Cela est possible très simplement grâce au filtre limit_choices_to qui adopte la syntaxe suivante :

 python
class Example(models.Model):
    foo = models.ForeignKey(<Modèle>, limit_choices_to = {'<attribut du modèle en question>': "<valeur>"}

Ce qui dans mon cas donne pour filtrer sur le type d'url et l'environnement :

 python
class Town(models.Model):
    """
    Town
    """
    ENVT_CHOICES = (
        ('1', 'VABF'),
        ('2', 'PREPROD'),
        ('3', 'PROD'),
    )
    STATE_CHOICES = (
        ('1', 'On construction'),
        ('2', 'On maintenance'),
        ('3', 'Open'),
        ('4', 'Closed'),
    )
    name = models.CharField(help_text="Provide the name of the town", max_length=100)
    description = models.CharField(help_text="You can provide extra information on the town", blank=True, max_length=100)
    prod_status = models.CharField("PROD status", help_text="State of the site on PROD environment", max_length=20, choices=STATE_CHOICES)
    prod_www = models.ForeignKey(Url, verbose_name="WWW Public URL", help_text="Public url of the site like www.velib.paris.fr", related_name="prod_www", limit_choices_to = {'urltype': 1, 'envt': 3})
    prod_abo = models.ForeignKey(Url, verbose_name="Subscription URL", help_text="HTTPS URL used for all sensible process like subscribption, my account, etc. Is often like https://abo-<town>.cyclocity.fr", related_name="prod_abo", limit_choices_to = {'urltype': 2, 'envt': 3})
    prod_admin = models.ManyToManyField(Url, verbose_name="Internal administration URL(s)", help_text="URL used to access back-office", related_name="prod_admin", limit_choices_to = {'urltype': 3, 'envt': 3} ) 
    prod_other = models.ManyToManyField(Url, verbose_name="Other URL(s)", help_text="Other urls related to the site like aliases related to the public url", related_name="prod_other", limit_choices_to = {'urltype': 4, 'envt': 3}, blank=True)
    prod_translation = models.ManyToManyField(Url, verbose_name="Translations URL", help_text="If site has translated versions, their public urls are listed here" ,related_name="prod_translation", limit_choices_to = {'urltype': 5, 'envt': 3}, blank=True)    

Comme le montre l'exemple de la documentation, ce filtre marche aussi de façon dynamique ou bien avec des objets Q pour les requêtes complexes :

 python
    limit_choices_to = {'pub_date__lte': datetime.now}

Du coup, le formulaire de création/édition d'une ville ne me présente plus qu'un nombre réduit d'urls pour un champ donné. Au pire, ma liste de choix aura un maximum d'éléments correspondant au nombre de villes déjà entrées dans le système. Il me faudrait affiner le filtre pour en plus ne présenter que les urls non déjà liées à une autre ville. Mais c'est moins évident et immédiat ;-)

En espérant que cela puisse être utile à d'autres...

Mon comparatif Django vs Symfony

Dans la mesure où au boulot les applications symfony commencent à se multiplier (on va passer de 1 à 2, restons modestes ;-) ) et que je songeais par ailleurs à recoder une appli existante en symfony pour des raisons de compétences internes à JCDecaux (Python/Django, c'est pas gagné a priori...), je me suis décidé à me (re)plonger dans Symfony.

Après quelques heures de lectures et fait le tutoriel en une heure et surtout le tutoriel Jobeet, voici ce que j'en retire par rapport à mon expérience sur Django. (pour être tout à fait honnête, j'ai consciencieusement suivi le tutoriel jusqu'à la fin du jour 7 - après, j'ai lu avec attention mais pas recopié les bouts de code).

Cela n'engage bien sur que moi, je suis ouvert à toute discussion constructive et cela ne se veut pas être un nid à troll ;-) N'ayant pas non plus lu toute la documentation Symfony, je peux dire des âneries ou des choses fausses car non présentées dans les documents que j'ai pu lire.

Sur les modèles :

  • Relations OneToOne, OneToMany ou ManyToMany : avantage Django puisque beaucoup plus limpide et pas besoin de déclarer les tables intermédiaires pour les relations ManyToMany. A contrario, cela peut paraître trop magique
  • Type de modèle : avantage Django. Symfony reste sur les types "de base" et il faut donc appeler ensuite un validateur pour valider le contenu d'un champ. Avec Django, c'est du tout en un par ex : models.UrlField qui ne stocke qu'une url et vérifie si elle est valide (et éventuellement si elle existe bien)

Routing :

  • Avantage Symfony sur les "Route Collection Class" : en gros en déclarant une fois par ex SfDoctrineCollectionRoute, cela vous met automatiquement les 7 méthodes à disposition (de base, new, create, edit, update, delete, show). Dans django, à ma connaissance, cela n'existe pas.
  • Avantage Django sur la flexibilité des urls (mais en est-ce vraiment un). On peut sortir du /module/action/param de Symfony. Ex-aequo sur la capacité à créer son schema d'url (merci Niko pour la correction)
  • Définition des routes : Avantage Symfony - les possibilités ont l'air plus fines (limité une route à une méthode par ex) et plus lisibles à mettre en oeuvre (les regexps des routes Django sont pas les plus simples à mon sens). Par contre, c'est sur que les routes Django sont du coup moins verbeuses que celle de Symfony (là encore, ça se discute)
  • Les urls par défaut fonctionnent de base sous Symfony. Le /module/action a pour avantage de pouvoir jouer tout de suite avec Symfony. Sous Django, cela n'est pas possible de sauter la case urls.py.

Fixtures :

  • Sous Symfony, il est intéressant de voir que l'on peut faire une boucle "for" pour insérer des fixtures en masse

Formulaires :

  • Symfony s'inspirant officiellement de django.forms, je ne reviendrais pas là dessus.

Templating :

  • Même si PHP peut être vu comme un langage de template en tant que tel, je suis plutôt adepte de l'approche de django.
  • Avantage Symfony sur les "partials". Je ne vois pas trop l'équivalent sous django de prime abord. C'est autre chose que l'héritage de template...
  • Avantage Symfony sur la gestion des "flash" (inspiré de Rails de mémoire). N'existe pas à ma connaissance sous Django.

Tests :

  • Pas de comparatif, je n'ai pas pris le temps de regarder ceux de django (aie, pas taper...)
  • En me basant sur la lecture j'ai l'impression que les tests de Symfony vont plus loin (tests unitaites + fonctionnels)

Authentification/Authorisation/Cache :

  • Ex-aequo ?

Gestion des "settings" :

  • Avantage Symfony (sous réserve d'aimer YAML) vu qu'il est possible de renseigner un fichier <module>/config/app.yml par ex. Ca évite de polluer le settings.py ou d'oublier des settings sur votre machine de dev lors d'un déploiement en prod.
  • Avantage Symfony sur la gestion des environnements sur le principe. Après tout dépend comment se fait le déploiement et qui le gère... (par ex, je ne donne pas les identifiants de prod aux équipes de dev au bureau...)

Interface d'admin :

  • Avantage Django je trouve, même si le fait qu'il faille maintenant toucher à admin.py rend l'accès à l'interface un peu plus fastidieux.
  • Le chevauchement de l'admin Symfony entre les données et le formulaire de tri sous Safari sur mon macbook n'aide pas non plus...

PHP / Python :

  • Même si j'arrive à lire la syntaxe PHP (que de progrès...), je trouve celle de python beaucoup plus agréable à lire et les $this-> et les foo::bar me laissent toujours perplexe ;-)
  • J'ai l'impression (donc totalement subjectif) que pour un résultat égal, il y aurait bcp plus de lignes dans un projet Symfony que Django

Plugins vs Applications redistribuables :

  • Dans django, tout est application et il est assez aisé de les redistribuer. Sous Symfony, cela prend le nom de plugins et je pense au final que c'est assez équivalent.
  • Symfony a un gros avantage, c'est que les plugins sont officiellement référencés. Pour django, faut passer par la case Google ou chercher dans les entrailes de github, bitbucket, google-code.

Globalement :

  • J'ai l'impression que Python/Django est de plus haut niveau (dans le sens macro/micro et non qualitatif) que PHP/Symfony. Je rajoute volontairement le langage car je me demande si ça ne vient pas également du langage et non uniquement du mode d'implémentation du framework. A l'inverse, on a peut être un niveau de granularité plus fin avec Symfony ?
  • J'ai une impression de "trop de fichiers" dans Symfony et de me noyer un peu dans cet ensemble.
  • Le tutoriel en une heure qui n'existe pas en version doctrine, c'est un peu dommage lorsqu'on veut partir sur Doctrine dès le départ
  • La double doc en version doctrine / propel est peut être source de confusion
  • Django et Symfony ont tous les deux une doc de qualité, même si parfois je m'y perds un peu (l'une comme l'autre).
  • Symfony est dans une logique beaucoup plus stricte au niveau MVC quand Django fait du MVT (Modèle Vue Template)

Pour bien faire, il faudrait faire un jobeet en version Django pour se faire une véritable idée sur les 2 frameworks. Pas sur d'avoir envie de faire ça dans l'immédiat par contre...

Personnellement :

  • J'y vois plus clair sur Symfony et c'était le but de l'exercice
  • je pense aller titiller un peu l'équipe de dev sur quelques points en particulier à mon retour de congés ;-)
  • Pour coder à titre perso, je vais rester sur Django

Au plaisir d'échanger avec vous maintenant (pour les qqs uns qui ne seraient pas en vacances) :-)

Pycon FR 2009 - Le programme est disponible !

L'AFPy (Association Francophone Python - http://www.afpy.org/ ) organise le week-end du 30/31 mai à la Vilette la 3ème version de Pycon FR (aka Conférence Python, version française).

Le programme varié et riche est disponible ici : http://pycon.fr/sessions - Il me reste encore à affiner mon programme de la journée entre les différentes conf :-)

Pour ma part, j'y serais à coup sûr le samedi et de façon peu probable le dimanche - au plaisir de vous y retrouver :-)

Django-frontendadmin ou comment éditer vos données en front-office

La description de django-frontendadmin est assez explicite :

django-frontendadmin is a set of templatetags to allow an easy and unobstrusive way to edit model-data in the frontend of your page

Prenons une page de mon projet start après intégration de django-frontendadmin :

Start et django-frontendadmin

D'un point de vu de code :

{% extends "base.html" %}
{% load frontendadmin_tags %}

{% block title %}
    {{ object.name }}
{% endblock title %}

{% block menu %}
    {% for th in all_theme %}
	    <li id="l{{ th.name }}"><a href="{{ th.get_absolute_url }}">{{ th.name }}</a></li>        
    {% endfor %}
        <li>{% frontendadmin_add all_theme "Ajouter un thème" %}</li>
{% endblock menu %}

{% block content %}
    <div id="breadcrumb">
        <a href="/">Home</a> &gt; <a href="/start/">Start</a> &gt; <a href="{{ object.theme.get_absolute_url }}">{{ object.theme.name }}</a> &gt; <a href="{{ object.get_absolute_url }}">{{ object.name }}</a>
    </div>
    <div class="category">
        <h3>
            {{ object.name }}
            ( {% frontendadmin_change object  "Modifier" %} - 
            {% frontendadmin_delete object  "Supprimer"%} )
        </h3>
        <ul>
        {% for bm in object.bookmark_set.all|dictsort:"order" %}
            <li>
                <a href="{{ bm.url }}">{{ bm.name }}</a>
                ( {% frontendadmin_change bm  "Modifier" %} - 
                {% frontendadmin_delete bm  "Supprimer"%} )
            </li>
        {% endfor %}
        </ul>
        {% frontendadmin_add object.bookmark_set.all "Ajouter un bookmark" %}
    </div>
{% endblock %}

En deux coups de cuillère à pot (rajout des lignes {% frontendadmin_* <objet / queryset> "label" %}), je peux donc très facilement ajouter/supprimer/modifier un favori ou une catégorie et ajouter un thème. Bien sûr, django-frontendadmin vérifie que vous avez bien les permissions de modifier le modèle en question avant de vous présenter les différents liens.

Si en plus, pour les formulaires d'ajout/modification/suppression, vous intégrez django-uniform (qui permet d'aisément utiliser Uni-Form dans les formulaires Django), il devrait y avoir moyen de faire quelque chose d'ergonomique :-)

Edit : Avec un bout de code, c'est plus parlant

Utiliser login_required() et cache_page() dans urls.py

En retravaillant sur Start suite au commentaire de Gilles (qui a encore disparu une nouvelle fois... ;-) ), j'avais réussi à basculer mes vues sous la forme de vues génériques mais il me restait à traiteur deux points :

En traitant le second point, la doc officielle de Django indiquant que pour limiter l'accès à une vue générique, il fallait faire un "wrapper" dans views.py pour y glisser le @login_required(). Un peu déçu de ce point, j'étais en train de refaire ma vue dans views.py quand David m'a indiqué ce snippet intitulé "login_required for a generic view in URLconf".

Dans la même veine et après consultation de David de du grand web, j'ai appliqué la même idée pour cache_page().

Au final, je n'ai donc plus de fichier views.py pour Start mais le fichier urls.py suivant :

 python
from django.conf.urls.defaults import *
from django.contrib.auth.decorators import login_required
from django.views.generic.list_detail import object_detail
from django.views.decorators.cache import cache_page
from start.models import Theme

theme_dict = { 
    'queryset': Theme.objects.all(),
    'extra_context': { 'all_theme': Theme.objects.all().order_by("order")},
}

urlpatterns = patterns('',
    (r'^(?P<slug>[a-z0-9-]+)/$', login_required(cache_page(object_detail, 60 * 5)), theme_dict),
    (r'^$', 'django.views.generic.simple.redirect_to', {'url': Theme.objects.get(is_default=True).slug }),
)

Mon souhait est donc exaucé - reste encore celui de Bruno...

PIL sous OSX

Pour installer PIL (Python Imaging Library) à partir de l'image fournie par pythonmac.org (j'ai eu des erreurs à la compilation en récupérant le fichier source et une info comme quoi le JPEG n'était pas supporté donc je me rabats sur l'image en espérant qu'elle fasse mieux)

  • Créer le lien symbolique suivant, sinon l'image refuse de s'installer... :
 bash
sudo ln -s /System/Library/Frameworks/Python.framework/ /Library/Frameworks/Python.framework
  • Installer PIL
  • Pour que PIL soit reconnu depuis le PYTHONPATH définit par défaut, faire un dernier lien symbolique :
 bash
sudo ln -s /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/PIL* /Library/Python/2.5/site-packages/
  • Tester que PIL est bien instalé (vous ne devez pas avoir d'erreur)
 bash
python -c "from PIL import Image"

Source : AppEngine: Installing PIL on OS X 10.5.3

Ajouté dans la section Tutoriels : Installer PIL sous Mac OS X

Bundles Textmate pour Django 1.0

Textmate propose 2 bundles pour Django : "Python Django" & "Python Django Templates" (cf le SVN des bundles TM). Or ces deux modules étaient restés valides pour les versions 0.9x de Django. Avec l'arrivée de Django 1.0, ces modules ont donc perdu de leur intérêt suite à l'arrivée du nouveau framework de formulaires et de la nouvelle interface d'administration.

Heureusement, une petite équipe s'est mise à mettre à jour ces deux bundles, qui sont disponibles sur bitbucket.org. Pour les avoir fraîchement installés mais pas encore joué avec, j'ai quand même été agréablement surpris par leur richesse sur la partie "Admin" et "Forms" notamment.

A suivre donc... :-)

- page 1 de 5

Fil des billets
Fil des commentaires