Configuración local de Django

Estoy tratando de usar local_setting en Django 1.2 , pero no funciona para mí. En este momento solo estoy agregando local_settings.py a mi proyecto.

settings.py

DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. 'NAME': 'banco1', # Or path to database file if using sqlite3. 'USER': 'root', # Not used with sqlite3. 'PASSWORD': '123', # Not used with sqlite3. 'HOST': 'localhost', # Set to empty string for localhost. Not used with sqlite3. 'PORT': '', # Set to empty string for default. Not used with sqlite3. } } 

local_settings.py

 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. 'NAME': 'banco2', # Or path to database file if using sqlite3. 'USER': 'root', # Not used with sqlite3. 'PASSWORD': '123', # Not used with sqlite3. 'HOST': 'localhost', # Set to empty string for localhost. Not used with sqlite3. 'PORT': '', # Set to empty string for default. Not used with sqlite3. } } 

El problema es que local_settings.py no anula settings.py . ¿Qué está mal?

No puedes simplemente agregar local_settings.py, tienes que importarlo explícitamente.

Al final de su configuración.py, agregue esto:

 try: from local_settings import * except ImportError: pass 

El bloque try / except está allí, por lo que Python simplemente ignora el caso cuando en realidad no ha definido un archivo local_settings.

Esta es la mejor práctica que pienso:

  • Importaciones local_settings desde la settings
  • local_settings anula las configuraciones específicas del entorno local, especialmente las variables DATABASES , SECRET_KEY , ALLOWED_HOSTS y DEBUG
  • pasar a la administración de django ordena la bandera --settings=local_settings

Podrías implementar local_settings como este:

 from settings import * DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. 'NAME': 'banco2', # Or path to database file if using sqlite3. 'USER': 'root', # Not used with sqlite3. 'PASSWORD': '123', # Not used with sqlite3. 'HOST': 'localhost', # Set to empty string for localhost. Not used with sqlite3. 'PORT': '', # Set to empty string for default. Not used with sqlite3. } } 

Algunos puntos clave adicionales:

  • settings.py está en el control de versiones, escrito de forma tal que está listo para ser utilizado por los contribuyentes
  • local_settings.py (o más comúnmente prod_settings.py ) NO está en el control de versión, y se usa en producción especificando --settings=prod_settings o similar.

Tocar el archivo de configuración de valores lo menos posible también facilita la actualización de su versión de django. Cuando actualice Django a la próxima versión, mire la diferencia en stock settings.py y en la suya, y realice las acciones necesarias según lo que haya cambiado. Los cambios en los valores predeterminados pueden ser importantes, y mientras menos toque el archivo settings.py original, será más fácil discernir los cambios en sentido ascendente.

Dado que el tema vuelve a aparecer, permítanme resumir por qué es posible que desee considerar este enfoque:

  • un archivo de configuración tonto es muy rápido y fácil de cambiar; Especialmente en un entorno de producción. No se requiere python: cualquier idiota puede saltar y cambiar la contraseña de la base de datos en un archivo que solo enumera nombres y valores; especialmente en comparación con un complejo archivo de configuración de Python lleno de misteriosos y peligrosos nombres BIGCAPS.

  • La settings la aplicación debe estar completamente separada del code de la aplicación. Puede poner un config.ini fuera de la raíz del repository y nunca más volver a preocuparse por un repo que reproduzca sus configuraciones, o sus configuraciones personales que contaminen el repository, o ese código inteligente en su configuración.py no lo haga en el repository en beneficio de todos los demás .

Esto no se aplicará a proyectos pequeños, pero en proyectos más grandes he llegado a la conclusión de que la estrategia local_settings simplemente no la corta; Con el tiempo, la progtwigción de la aplicación es suficiente para que sea difícil de manejar; principalmente a medida que los ajustes se convierten en derivados y / o codependientes. Puede haber buenas justificaciones para que las configuraciones reaccionen de acuerdo con las configuraciones locales, lo que obliga a que la importación de un archivo local_settings hacia la mitad de settings.py . Encuentro que las cosas empiezan a complicarse a medida que eso sucede.

Mi solución actual es usar un archivo de config , lo apodo “local.ini”. Solo contiene aquellos valores que realmente cambian entre las instancias implementadas. No hay código: son solo valores y booleanos:

 [global] domain = 127.0.0.1:8000 database_host = 127.0.0.1 database_name = test_database debug = Yes google_analytics_id = UA-DEV-1 payments = testing use_cdn = No 

Con esto en su lugar, puedo tratar el settings.py como cualquier otro código de aplicación: modificarlo, registrarlo y desplegarlo sin tener que preocuparme por probar cualquier código que pueda estar al acecho en un código python local_settings. Mi settings.py está libre de condiciones de carrera que surgen cuando la configuración posterior depende de la configuración local, y puedo activar y desactivar las funciones escribiendo código lineal fácil de seguir. No más ajustes rápidos en el archivo local_settings cuando olvidé agregar un nuevo valor, y no más archivos daves_local_settings.py y bobs_local_settings.py que se arrastran en el repository.

 from ConfigParser import RawConfigParser parser = RawConfigParser() APPLICATION_ROOT = path.abspath(path.dirname(__file__)) parser.readfp(open(path.join(APPLICATION_ROOT, 'local.ini'))) # simple variables DATABASE_HOST = parser.get('global', 'database_host') DATABASE_NAME = parser.get('global', 'database_name') # interdependencies from version import get_cdn_version CDN = 'd99phdomw5k72k.cloudfront.net' if parser.getboolean('global', 'use_cdn'): STATIC_URL = '/{}/static/{}/'.format(CDN, get_cdn_version()) else: STATIC_URL = '/static/' # switches payments = parser.get('global', 'payments') if payments == 'testing': PAYMENT_GATEWAY_ENDPOINT = 'https://api.sandbox.gateway.com' else: PAYMENT_GATEWAY_ENDPOINT = 'https://api.live.gateway.com' 

Si se encuentra con un BOFH , como tuve en una ocasión, se entusiasmó particularmente con la capacidad de pegar local.ini en el directorio /etc como /etc/ourapp.ini y así mantener el directorio de la aplicación como una /etc/ourapp.ini exportación de repository. Claro que podrías hacer eso con un local_settings.py pero lo último que quería hacer era meterse con el código de Python. Un simple archivo de configuración que él podría manejar.

Guardé una copia de __local_settings.py :

  • local_settings.py se ignora en el control de versión, pero no __local_settings.py
  • actualice README.md para informar al equipo sobre cómo configurar: cp {__,}local_settings.py (que hace una copia para sus local_settings)

En el pasado

Solía ​​importar esas configuraciones.

 # settings.py DATABASE = {...} try: from .local_settings import * except ImportError: pass 

ahora

Acabo de importar la configuración de local_settings.py .

Y con el siguiente comando: python manage.py runserver --settings=.local_settings .

 # local_settings.py & __local_settings.py from .settings import * DATABASE = {...} 

Y ya que, por lo general, no interactúo con manage.py directamente, porque algunos parámetros son explícitamente necesarios para mí (por ejemplo, address:port ). Por lo tanto, puse todos esos comandos en mi Makefile .

Por ejemplo, aquí está mi Makefile:

 run: python manage.py runserver 0.0.0.0:8000 --settings=.local_settings sh: python manage.py shell_plus --settings=.local_settings dep: npm install pip install -r requirements.txt 

Así:

 make dep make sh make run 

Conclusión

Siempre que no esté utilizando Makefile como su flujo de trabajo, entonces puede usar el método anterior, pero si está utilizando Makefile, entonces creo que es mejor ser más explícito en su Makefile.

Antes de ejecutar el servidor haga

export DJANGO_SETTINGS_MODULE=your_app_name.local_settings donde tu_app_name debe ser reemplazado por el nombre de tu aplicación. Y no te olvides de hacer

 from settings import * 

en su archivo local_settings.py

Encontré la solución similar. Esta es mi configuración para este caso:

settings.py:

 DEBUG = False try: from local_settings import * except ImportError: pass if DEBUG is False: ALLOWED_HOSTS = ['sth.com'] DATABASES = { .... } 

local_settings.py:

 from settings import * ALLOWED_HOSTS = ['*'] DEBUG = True DATABASES = { ... } 

Otro enfoque más es utilizar python-dotenv y las variables de entorno para personalizar las configuraciones para diferentes entornos.

Cree el archivo .env junto a su settings.py :

 # .env SECRET_KEY=your-secret-key DATABASE_PASSWORD=your-database-password 

Agregue el siguiente código a su settings.py :

 # settings.py from dotenv import load_dotenv load_dotenv() # OR, explicitly providing path to '.env' from pathlib import Path # python 3.4+ env_path = Path('.') / '.env' load_dotenv(dotenv_path=env_path) 

En este punto, las claves / valores .env archivo .env están presentes como variables de entorno y se puede acceder a os.getenv() cómodamente a través de os.getenv() :

 # settings.py import os SECRET_KEY = os.getenv('SECRET_KEY') DATABASE_PASSWORD = os.getenv('DATABASE_PASSWORD') 

Agrega esto al final del archivo settings.py

 try: from .local_settings import * except ImportError: pass 

Y cree el archivo local_settings.py con su nueva configuración, por ejemplo

 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. 'NAME': 'banco2', # Or path to database file if using sqlite3. 'USER': 'root', # Not used with sqlite3. 'PASSWORD': '123', # Not used with sqlite3. 'HOST': 'localhost', # Set to empty string for localhost. Not used with sqlite3. 'PORT': '', # Set to empty string for default. Not used with sqlite3. } }