web-dev-qa-db-fra.com

Comment gérer les paramètres locaux et de production dans Django?

Quelle est la méthode recommandée pour gérer les paramètres du développement local et du serveur de production? Certaines d'entre elles (telles que les constantes, etc.) peuvent être modifiées/accessibles dans les deux, mais certaines d'entre elles (telles que les chemins d'accès aux fichiers statiques) doivent rester différentes et ne doivent donc pas être remplacées à chaque déploiement du nouveau code.

Actuellement, j'ajoute toutes les constantes à settings.py. Mais chaque fois que je change une constante localement, je dois la copier sur le serveur de production et éditer le fichier pour y apporter des modifications spécifiques à la production ... :( 

Edit: il semble qu'il n'y ait pas de réponse standard à cette question, j'ai accepté la méthode la plus populaire.

265
akv

Dans settings.py:

try:
    from local_settings import *
except ImportError as e:
    pass

Vous pouvez remplacer ce qui est nécessaire dans local_settings.py; alors il devrait rester en dehors de votre contrôle de version. Mais puisque vous parlez de copier, je suppose que vous n'en utilisez aucun;)

126
ohnoes

Deux Scoops de Django: Bonnes pratiques pour Django 1.5 suggère d'utiliser le contrôle de version pour vos fichiers de paramètres et de les stocker dans un répertoire séparé:

project/
    app1/
    app2/
    project/
        __init__.py
        settings/
            __init__.py
            base.py
            local.py
            production.py
    manage.py

Le fichier base.py contient les paramètres courants (tels que MEDIA_ROOT ou ADMIN), alors que local.py et production.py ont des paramètres spécifiques au site:

Dans le fichier de base settings/base.py:

INSTALLED_APPS = (
    # common apps...
)

Dans le fichier de paramètres de développement local settings/local.py:

from project.settings.base import *

DEBUG = True
INSTALLED_APPS += (
    'debug_toolbar', # and other apps for local development
)

Dans le fichier de paramètres de production du fichier settings/production.py:

from project.settings.base import *

DEBUG = False
INSTALLED_APPS += (
    # other apps for production site
)

Ensuite, lorsque vous exécutez Django, vous ajoutez l'option --settings:

# Running Django for local development
$ ./manage.py runserver 0:8000 --settings=project.settings.local

# Running Django Shell on the production site
$ ./manage.py Shell --settings=project.settings.production

Les auteurs du livre ont également mis en place un exemple de modèle de mise en page de projet sur Github.

268
Rudolf Olah

Au lieu de settings.py, utilisez cette disposition:

.
└── settings/
    ├── __init__.py  <= not versioned
    ├── common.py
    ├── dev.py
    └── prod.py

common.py est l'endroit où réside la plupart de votre configuration.

prod.py importe tout du commun et remplace tout ce dont il a besoin pour remplacer:

from __future__ import absolute_import # optional, but I like it
from .common import *

# Production overrides
DEBUG = False
#...

De même, dev.py importe tout de common.py et remplace tout ce dont il a besoin.

Enfin, __init__.py est l'endroit où vous choisissez les paramètres à charger, et c'est également où vous stockez les secrets (ce fichier ne doit donc pas être versionné):

from __future__ import absolute_import
from .prod import *  # or .dev if you want dev

##### Django SECRETS
SECRET_KEY = '(3Gd6shenud@&57...'
DATABASES['default']['PASSWORD'] = 'f9kGH...'

##### OTHER SECRETS
AWS_SECRET_ACCESS_KEY = "h50fH..."

Ce que j'aime dans cette solution c'est:

  1. Tout est dans votre système de gestion de versions, sauf les secrets
  2. La plupart des configurations se trouvent à un endroit: common.py.
  3. Les éléments spécifiques à Prod vont dans prod.py, les éléments spécifiques à dev vont à dev.py. C'est simple.
  4. Vous pouvez remplacer des éléments de common.py dans prod.py ou dev.py et vous pouvez remplacer n'importe quoi dans __init__.py.
  5. C'est python simple. Pas de réimportations.
63
MiniQuark

J'utilise une version légèrement modifiée du style de paramètres "if DEBUG" publié par Harper Shelby. Évidemment, selon l’environnement (win/linux/etc.), Le code devra peut-être être légèrement modifié.

J'utilisais autrefois le "if DEBUG" mais j'ai constaté que je devais parfois faire des tests avec DEUBG réglé sur False. Ce que je voulais vraiment distinguer si l'environnement était la production ou le développement, ce qui m'a donné la liberté de choisir le niveau DEBUG.

PRODUCTION_SERVERS = ['WEBSERVER1','WEBSERVER2',]
if os.environ['COMPUTERNAME'] in PRODUCTION_SERVERS:
    PRODUCTION = True
else:
    PRODUCTION = False

DEBUG = not PRODUCTION
TEMPLATE_DEBUG = DEBUG

# ...

if PRODUCTION:
    DATABASE_Host = '192.168.1.1'
else:
    DATABASE_Host = 'localhost'

Je considère toujours cette façon de mettre en place un travail en cours. Je n'ai pas vu de moyen unique de gérer les paramètres Django qui couvrent toutes les bases et qui ne soit en même temps pas compliqué à installer (les méthodes de fichiers de paramètres 5x ne me dérangent pas).

20
T. Stone

J'utilise settings_local.py et settings_production.py. Après avoir essayé plusieurs options, j'ai constaté qu'il était facile de perdre du temps avec des solutions complexes lorsque le simple fait de disposer de deux fichiers de paramètres est simple et rapide.

Lorsque vous utilisez mod_python/mod_wsgi pour votre projet Django, vous devez le pointer vers votre fichier de paramètres. Si vous le dirigez vers app/settings_local.py sur votre serveur local et app/settings_production.py sur votre serveur de production, la vie devient alors plus facile. Modifiez simplement le fichier de paramètres approprié et redémarrez le serveur (le serveur de développement Django redémarrera automatiquement).

14
Kai

Je gère mes configurations à l'aide de Django-split-settings

C'est un remplacement instantané des paramètres par défaut. C'est simple, mais configurable. Et le refactoring de vos paramètres existants n'est pas nécessaire.

Voici un petit exemple (fichier example/settings/__init__.py):

from split_settings.tools import optional, include
import os

if os.environ['Django_SETTINGS_MODULE'] == 'example.settings':
    include(
        'components/default.py',
        'components/database.py',
        # This file may be missing:
        optional('local_settings.py'),

        scope=globals()
    )

C'est tout.

Mettre à jour

J'ai écrit un article blog sur la gestion des paramètres Django avec Django-split-sttings. Regarde!

7
sobolevn

Le problème avec la plupart de ces solutions est que vous avez soit appliqué vos paramètres locaux avant les paramètres communs, soit après eux.

Il est donc impossible de passer outre des choses comme

  • les paramètres spécifiques à env définissent les adresses du pool memcached et, dans le fichier de paramètres principal, cette valeur est utilisée pour configurer le backend du cache
  • les paramètres spécifiques à env ajoutent ou suppriment les applications/middleware à ceux par défaut

en même temps.

Une solution peut être implémentée en utilisant des fichiers de configuration de type "ini" avec la classe ConfigParser. Il prend en charge plusieurs fichiers, l’interpolation de chaînes paresseuse, les valeurs par défaut et de nombreux autres avantages . Une fois que plusieurs fichiers ont été chargés, plusieurs fichiers peuvent être chargés et leurs valeurs remplacent les précédentes, le cas échéant.

Vous chargez un ou plusieurs fichiers de configuration, en fonction de l'adresse de la machine, des variables d'environnement et même des valeurs contenues dans des fichiers de configuration précédemment chargés. Ensuite, vous utilisez simplement les valeurs analysées pour renseigner les paramètres. 

Une stratégie que j'ai utilisée avec succès a été:

  • Charger un fichier defaults.ini par défaut
  • Vérifiez le nom de l'ordinateur et chargez tous les fichiers correspondant au nom de domaine complet inversé, de la correspondance la plus courte à la correspondance la plus longue (donc, j'ai chargé net.ini, puis net.domain.ini, puis net.domain.webserver01.ini, chacun d'entre eux remplaçant éventuellement les valeurs précédentes). Ce compte est également destiné aux ordinateurs des développeurs, afin que chacun puisse configurer son pilote de base de données préféré, etc. pour le développement local.
  • Vérifiez s'il existe un "nom de cluster" déclaré, et dans ce cas, chargez cluster.cluster_name.ini, qui peut définir des éléments tels que les IP de base de données et de cache

En guise d'exemple, vous pouvez définir une valeur de "sous-domaine" par env, qui est ensuite utilisée dans les paramètres par défaut (sous la forme hostname: %(subdomain).whatever.net) pour définir tous les noms d'hôte et cookies nécessaires au fonctionnement de Django.

C'est comme DRY que je pouvais obtenir, la plupart des fichiers (existants) n'avaient que 3 ou 4 paramètres. En plus de cela, je devais gérer la configuration du client, donc un ensemble supplémentaire de fichiers de configuration (avec des noms tels que les noms de bases de données, les utilisateurs et les mots de passe, le sous-domaine attribué, etc.) existait, un ou plusieurs par client.

On peut réduire ce nombre au minimum ou au maximum, il suffit de mettre dans le fichier de configuration les clés à configurer pour chaque environnement, et dès qu’une nouvelle configuration est nécessaire, insérez la valeur précédente dans la configuration par défaut et remplacez-la. Où il faut.

Ce système s'est avéré fiable et fonctionne bien avec le contrôle de version. Il est utilisé depuis longtemps pour gérer deux grappes d'applications distinctes (au moins 15 instances distinctes du site Django par machine), avec plus de 50 clients, où les grappes changeaient de taille et de membres en fonction de l'humeur de l'administrateur système. .

6
rewritten

Je travaille aussi avec Laravel et j'aime la mise en œuvre là-bas. J'ai essayé de l'imiter et de le combiner avec la solution proposée par T. Stone (voir ci-dessus):

PRODUCTION_SERVERS = ['*.webfaction.com','*.whatever.com',]

def check_env():
    for item in PRODUCTION_SERVERS:
        match = re.match(r"(^." + item + "$)", socket.gethostname())
        if match:
            return True

if check_env():
    PRODUCTION = True
else:
    PRODUCTION = False

DEBUG = not PRODUCTION

Peut-être que quelque chose comme ceci pourrait vous aider.

4
Robert Kuzma

Rappelez-vous que settings.py est un fichier de code en direct. En supposant que vous n’ayez pas défini DEBUG en production (ce qui est une pratique exemplaire), vous pouvez effectuer les opérations suivantes:

if DEBUG:
    STATIC_PATH = /path/to/dev/files
else:
    STATIC_PATH = /path/to/production/files

Assez basique, mais vous pouvez théoriquement atteindre un niveau de complexité basé uniquement sur la valeur de DEBUG - ou sur toute autre vérification de code ou de variable que vous souhaitez utiliser.

4
Harper Shelby

J'utilise une variante de ce que jpartogi a mentionné ci-dessus, que je trouve un peu plus courte:

import platform
from Django.core.management import execute_manager 

computername = platform.node()

try:
  settings = __import__(computername + '_settings')
except ImportError: 
  import sys
  sys.stderr.write("Error: Can't find the file '%r_settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run Django-admin.py, passing it your settings module.\n(If the file local_settings.py does indeed exist, it's causing an ImportError somehow.)\n" % (computername, __file__))
  sys.exit(1)

if __== "__main__":
  execute_manager(settings)

Sur chaque ordinateur (développement ou production), j’ai le fichier hostname_settings.py approprié qui est chargé dynamiquement.

3
stratosgear

Il y a aussi les paramètres Django Classy. Personnellement, j'en suis un grand fan. Il a été construit par l'une des personnes les plus actives de l'IRC Django. Vous utiliseriez des variables d'environnement pour régler les choses.

http://Django-classy-settings.readthedocs.io/en/latest/

3
SudoKid

Ma solution à ce problème est aussi un peu un mélange de certaines solutions déjà énoncées ici:

  • Je garde un fichier appelé local_settings.py qui a le contenu USING_LOCAL = True dans dev et le USING_LOCAL = False dans prod
  • Dans settings.py je fais une importation sur ce fichier pour obtenir le paramètre USING_LOCAL

Je base alors tous mes paramètres dépendants de l'environnement sur celui-ci:

DEBUG = USING_LOCAL
if USING_LOCAL:
    # dev database settings
else:
    # prod database settings

Je préfère cela plutôt que d'avoir deux fichiers settings.py distincts que je dois conserver car je peux garder mes paramètres structurés dans un seul fichier plus facilement que de les répartir sur plusieurs fichiers. Ainsi, lorsque je mets à jour un paramètre, je n'oublie pas de le faire pour les deux environnements.

Bien sûr, chaque méthode a ses inconvénients et celle-ci ne fait pas exception. Le problème ici est que je ne peux pas écraser le fichier local_settings.py à chaque fois que je mets mes modifications en production, ce qui signifie que je ne peux pas simplement copier tous les fichiers à l'aveuglette, mais c'est une chose avec laquelle je peux vivre.

3
Miguel Ventura

Pour la plupart de mes projets, j'utilise le modèle suivant:

  1. Créez settings_base.py où je stocke les paramètres communs à tous les environnements 
  2. Chaque fois que je dois utiliser un nouvel environnement avec des exigences spécifiques, je crée un nouveau fichier de paramètres (par exemple, settings_local.py) qui hérite du contenu de settings_base.py et remplace/ajoute les variables de paramètres appropriées (from settings_base import *)

(Pour exécuter manage.py avec le fichier de paramètres personnalisé, utilisez simplement l'option --settings de la commande: manage.py <command> --settings=settings_you_wish_to_use.py)

3
dzida

Pour utiliser différentes configurations settings dans différents environnements, créez un fichier de paramètres différent. Et dans votre script de déploiement, démarrez le serveur à l'aide de --settings=<my-settings.py> paramètre, via lequel vous pouvez utiliser différents paramètres sur différents environnements.

Avantages de l’utilisation de cette approche:

  1. Vos paramètres seront modulaires en fonction de chaque environnement

  2. Vous pouvez importer le master_settings.py contenant la configuration de base dans le environmnet_configuration.py et remplacer les valeurs que vous souhaitez modifier dans cet environnement.

  3. Si vous avez une grande équipe, chaque développeur peut avoir son propre local_settings.py qu’il peut ajouter au référentiel de code sans risque de modification de la configuration du serveur. Vous pouvez ajouter ces paramètres locaux à .gitnore si vous utilisez git _ ou .hginore si vous Mercurial pour Contrôle de version (ou un autre). De cette façon, les paramètres locaux ne feront même pas partie de la base de code elle-même.

2
Moinuddin Quadri

1 - Créez un nouveau dossier dans votre application et nommez ses paramètres.

2 - Créez maintenant un nouveau fichier init . Py et écrivez dedans

    from .base import *

    try:

        from .local import *

    except:

        pass

     try:

         from .production import *

     except:

         pass

3 - Créez trois nouveaux fichiers dans les dossiers de paramètres nom local.py et production.py et base.py

4 - Dans base.py, copiez tout le contenu du dossier précédent settings.p et renommez-le avec quelque chose de différent. Disons old_settings.py

5 - Dans base.py, changez votre chemin BASE_DIR pour qu'il pointe vers votre nouveau chemin de réglage

Ancien chemin-> BASE_DIR = os.path.dirname (os.path.dirname (os.path.abspath ( fichier )))

Nouveau chemin -> BASE_DIR = os.path.dirname (os.path.dirname (os.path.dirname (os.path.abspath ( fichier )))

de cette manière, le répertoire du projet peut maintenant être structuré et être gérable entre la production et le développement local.

1
Jack Ryan

Si vous utilisez git ou un autre VCS pour envoyer des codes de local à serveur, vous pouvez également ajouter le fichier de paramètres à .gitignore.

Cela vous permettra d'avoir un contenu différent aux deux endroits sans aucun problème. SO sur le serveur, vous pouvez configurer une version indépendante de settings.py. Toute modification apportée sur le serveur local ne sera pas répercutée sur le serveur et inversement.

En outre, il supprimera également le fichier settings.py de github, le gros défaut, ce que beaucoup de débutants ont fait.

1
sprksh

Je le différencie dans manage.py et crée deux fichiers de paramètres distincts: local_settings.py et prod_settings.py. 

Dans manage.py, je vérifie si le serveur est un serveur local ou un serveur de production. S'il s'agit d'un serveur local, il chargera local_settings.py et il s'agira d'un serveur de production, prod_settings.py. En gros, voici à quoi cela ressemblerait:

#!/usr/bin/env python
import sys
import socket
from Django.core.management import execute_manager 

ipaddress = socket.gethostbyname( socket.gethostname() )
if ipaddress == '127.0.0.1':
    try:
        import local_settings # Assumed to be in the same directory.
        settings = local_settings
    except ImportError:
        import sys
        sys.stderr.write("Error: Can't find the file 'local_settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run Django-admin.py, passing it your settings module.\n(If the file local_settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
        sys.exit(1)
else:
    try:
        import prod_settings # Assumed to be in the same directory.
        settings = prod_settings    
    except ImportError:
        import sys
        sys.stderr.write("Error: Can't find the file 'prod_settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run Django-admin.py, passing it your settings module.\n(If the file prod_settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
        sys.exit(1)

if __== "__main__":
    execute_manager(settings)

J'ai trouvé qu'il était plus facile de séparer le fichier de paramètres en deux fichiers distincts au lieu de faire beaucoup de ifs dans le fichier de paramètres.

1
Joshua Partogi

J'ai eu mes paramètres divisés comme suit 

settings/
     |
     |- base.py
     |- dev.py
     |- prod.py  

Nous avons 3 environnements 

  • dev
  • mise en scène
  • production 

Évidemment, la mise en scène et la production devraient avoir le maximum d’environnements similaires. Nous avons donc gardé prod.py pour les deux.

Mais il y avait un cas où je devais identifier le serveur en cours d'exécution est un serveur de production. @T. La réponse de Stone m'a aidé à rédiger un chèque comme suit. 

from socket import gethostname, gethostbyname  
PROD_HOSTS = ["webserver1", "webserver2"]

DEBUG = False
ALLOWED_HOSTS = [gethostname(), gethostbyname(gethostname()),]


if any(Host in PROD_HOSTS for Host in ALLOWED_HOSTS):
    SESSION_COOKIE_SECURE = True
    CSRF_COOKIE_SECURE = True  
1
Kishor Pawar

Je pense que la meilleure solution est suggérée par @T. Stone, mais je ne sais pas pourquoi n'utilise pas le drapeau DEBUG dans Django. J'écris le code ci-dessous pour mon site web:

if DEBUG:
    from .local_settings import *

Les solutions simples sont toujours meilleures que les solutions complexes.

0
seyedrezafar

Créer plusieurs versions de settings.py est un anti modèle pour 12 Méthodologie de Factor App . Utilisez python-decouple ou Django-environ .

0
Mustapha-Belkacim