En Django, le fichier settings.py, c’est juste du Python 5


On a beau répêter dans la doc, “Django is just Python”, c’est difficile de s’y faire. Surtout dans le fichier settigns.py: c’est vrai que le paramétrage, c’est quelque chose qu’on a l’habitude d’être typiquement déclaratif.

Rappel donc, le fichier settings.py, c’est juste du Python.

Ça veut dire qu’on peut faire ça en début de fichier:

import os
# répérer le dossier du projet
ROOT_DIR = os.path.dirname(os.path.realpath(__file__))
 
Et ça un peut partout dans le projet pour éviter les d'avoir des chemins absolus en dur:
 
STATIC_ROOT = os.path.join(ROOT_DIR, 'static')

On peut aussi faire des choses comme celle-ci, pour avoir un comportement spécial en mode debug:

if DEBUG:
 
    # on retire le dernier middleware
    MIDDLEWARE_CLASSES = [:-1]
    #et on en rajoute un au début
    MIDDLEWARE_CLASSES = (
        'libs.middlewares.MonMiddlewareKilebo',
    ) + MIDDLEWARE_CLASSES

Et si un settings n’existe pas, on peut l’inventer pour le réutiliser partout dans son code ailleurs:

SERVER_POOL = (
    ('8.8.8.8', "sametmax.com"),
    ('8.8.4.4', "cnd.sametmax.com"),
    ('208.67.222.222', 'staging.sametmax.com'),
    ('208.67.220.220', "dev.sametmax.com")
)

Et même se faciliter la vie:

SERVER_POOL_DICT = dict(SERVER_POOL)

Dans le même genre on peut faire des calculs:

CINQ_MINUTES = 60 * 5
...
CACHE_MIDDLEWARE_SECONDS = CINQ_MINUTES * 2

Et bien entendu, on peut splitter son fichier de settings en plusieurs fichiers. Il y a le maintenant classique fichier de settings local qui est différent sur chaque marchine, et qu’on importe en fin de fichier:

try:
    from settings_local import *
except ImportError:
    pass

Ca permet de mettre les paramètres de la base de données dans settings_local.py.

Mais on oublie souvent que peut tout à fait récupérer les paramètres depuis un fichier non Python.

Récupérer des valeurs dans un fichiers ini ? Fastoche !

import ConfigParser
config = ConfigParser.RawConfigParser()
config.readfp('/chemin/vers/fichier.ini')
locals().update(config.items('section'))

5 thoughts on “En Django, le fichier settings.py, c’est juste du Python

  • Brutasse

    Les CINQ_MINUTES ressemblent plutôt à CINQ_HEURES :)

    Le try… except à la fin du settings.py est un anti-pattern. C.f. slides 75 et suivantes. Enfin chacun a son “one true way”, c’est un sujet où tout le monde a sa façon de faire. La mienne en ce moment consiste à se baser sur des variables d’environnement, ce qui a l’avantage ne ne nécessiter aucune modification de code pour passer de dev à production. Ça mériterait probablement sa série d’articles.

    Par ailleurs, l’utilisation de locals().update(…) est puni de 15 récitations du Zen of Python.

  • Max

    @brutasse

    Et ça te dirais pas de devenir contributeur pertinent à Sam&Max pour nous pondre cet article justement ? :)

  • Sam Post author

    Très bon idée: http://sametmax.com/appel-a-contributeurs-impertinents/ :-)

    Et merci pour la coquille, c’est corrigé.

    Par contre le mec (au passage pour ceux qui se demandent, c’est un des main dev du framework) qui a fait cette présentation est de mauvaise foi:

    https://speakerdeck.com/u/jacobian/p/the-best-and-worst-of-django

    Exemple de concrete base class qui ignore complètement l’option abstract jusqu’à finalement l’insérer sur un slide à l’arrache pour faire honête. Mais alors l’interêt du point précédent en 10 slides ?

    Il mélange mésusage des fonctionnalité et critique de la fonctionnalité elle-même.

    Introduction de SOLR comme base NOSQL ? Heu… Ok… Je vous présente ma nouvelle base de données NOSQL: le fichier plat. SOLR est un moteur optimisé pour la recherche de texte, pas le stockage de données arbitraires. Pourquoi pas utiliser REDIS pour faire du relationel, et MySQL pour du map-reduce tant qu’on y est ? Oui c’est possible…

    “Ceux qui ne comprennent pas le PYTHON_PATH sont condamnés à l’échec”

    Oui. Certes. Quel rapport avec Django ? C’est vrai pour tout projet Python.

    “Delete manage.py”

    Et le slide d’après, la solution c’est d’utiliser une variable d’env… pour manage.py. O_o. Aucune autre explication. Il a bu ?

    “local_settings est un anti pattern parce qu’il n’est jamais mis dans le VCS”

    Comme les fichiers tmp, les binaires, les fichiers de projets de mon IDE, etc. Se sont des mauvaises idées aussi alors ? Faut les interdire ?

    Sinon, lui il met sa secret key dans sont repo pushé sur Github ?

    “Why is your staging env different from your production ?”

    Quick and dirty hacking. Different OS. DEBUG = 3, autologging middleware, verbose logging, automatic permissions for file uploads…

    Et au final, sa solution, utiliser une variable d’env (qui est tout à fait une bonne idée, et fort pratique), n’invalide PAS DU TOUT l’usage de try import. C’est juste un complement. Surtout quand on a 4 sites dans le même projet, cas dans lequel on a 4 fichiers de config, et on ne va certainement pas forcer le module settings avec une variable d’env.

    J’espère vraiment que ces incohérences sont ici parce que je n’ai pas le contenu du discours qui va avec les slides.

  • Brutasse

    @Max, @Sam

    J’ai déjà un blog (bruno.im) que ce genre d’article pourrait faire revivre, merci pour la proposition :)

    @Sam

    Il manque effectivement pas mal de contexte.

    “Ceux qui ne comprennent pas le PYTHON_PATH sont condamnés à l’échec” – le rapport avec Django c’est qu’avant 1.4, Django (plus spécifiquement manage.py) modifiait le python path pour qu’on puisse importer project.app ou app indifféremment. D’où la volonté de supprimer manage.py, il a finalement été corrigé avec la nouvelle arborescence de projet introduite avec Django 1.4.

    Le souci avec local_settings c’est qu’avec un try: except ImportError il est impossible d’étendre les settings par défaut, on ne peut que les redéfinir. Exemple, pour ajouter la debug_toolbar en local, il faut modifier INSTALLED_APPS et MIDDLEWARE_CLASSES. L’alternative est d’avoir des settings par défaut (default_settings) et pour chaque environnement, importer ces settings et les modifier à loisir (INSTALLED_APPS += ('debug_toolbar',)). Ce qui est la solution décrite par Jacob. Le point est d’importer les settings de base depuis les settings spécifiques et non l’inverse.

    Il est effectivement possible qu’il mette sa secret_key dans settings/production.py, pushé sur github. À mon avis un paquet de gens font ça. Ce n’est pas une solution non plus, et justement les variables d’environnement permettent de gérer facilement la séparation entre secrets liés à l’environnement et code applicatif.

  • Sam Post author

    Sur les gros projets, j’ai jusqu’à 3 niveaux d’import:

    – common_settings.py (default pour tous)
    – site_settings.py (default pour le site)
    – site_settings_local.py (les choses à mettre qu’en local).

    Et mes fichiers settings_local.py font ceci:

    import settings
     
    settings.INSTALLED_APPS = ('debug_toolbar',)).

    Finalement ça revient au même. C’est juste une question de sémantique.

    Sinon il est très chouette ton blog. Tu devrais poster quelques articles sur pythonlive.fr et le reddit pythonfr.

Leave a comment

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <pre> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Des questions Python sans rapport avec l'article ? Posez-les sur IndexError.