¿Cómo administrar la configuración local vs producción en Django?


¿Cuál es la forma recomendada de manejar la configuración para el desarrollo local y el servidor de producción? Algunos de ellos (como constantes, etc.) se pueden cambiar/acceder en ambos, pero algunos de ellos (como rutas a archivos estáticos) deben permanecer diferentes, y por lo tanto no deben sobrescribirse cada vez que se implemente el nuevo código.

Actualmente, estoy agregando todas las constantes a settings.py. Pero cada vez que cambio alguna constante localmente, tengo que copiarla al servidor de producción y editar el archivo para cambios específicos de producción... :(

Editar: parece que no hay una respuesta estándar a esta pregunta, he aceptado el método más popular.

Author: guaka, 2009-10-26

20 answers

En settings.py:

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

Puede anular lo que necesita en local_settings.py; debe permanecer fuera de su control de versiones entonces. Pero ya que mencionas copiar, supongo que no usas ninguno;)

 118
Author: ohnoes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-29 10:38:48

Dos cucharadas de Django: Mejores prácticas para Django 1.5 sugiere usar control de versiones para sus archivos de configuración y almacenar los archivos en un directorio separado:

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

El archivo base.py contiene configuraciones comunes (como MEDIA_ROOT o ADMIN), mientras que local.py y production.py tienen configuraciones específicas del sitio:

En el archivo base settings/base.py:

INSTALLED_APPS = (
    # common apps...
)

En el archivo de configuración de desarrollo local settings/local.py:

from project.settings.base import *

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

En el archivo archivo de configuración de producción settings/production.py:

from project.settings.base import *

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

Luego, cuando ejecuta django, agrega la opción --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

Los autores del libro también han puesto una plantilla de diseño de proyecto de muestra en Github.

 262
Author: Rudolf Olah,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-18 01:09:36

En lugar de settings.py, utilice este diseño:

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

common.py es donde vive la mayor parte de su configuración.

prod.py importa todo de común, y anula lo que necesita para anular:

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

# Production overrides
DEBUG = False
#...

Del mismo modo, dev.py importa todo desde common.py y anula todo lo que necesita.

Finalmente, __init__.py es donde decide qué configuración cargar, y también es donde almacena secretos (por lo tanto, este archivo no debe ser versioned):

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..."

Lo que me gusta de esta solución es:

  1. Todo está en su sistema de versiones, excepto secrets
  2. La mayor parte de la configuración está en un solo lugar: common.py.
  3. Las cosas específicas de Prod entran prod.py, las cosas específicas de dev entran dev.py. Es simple.
  4. Puedes anular cosas de common.py en prod.py o dev.py, y puedes anular cualquier cosa en __init__.py.
  5. Es python sencillo. No hay hacks de reimportación.
 61
Author: MiniQuark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-09 19:48:26

Utilizo una versión ligeramente modificada del estilo de configuración "if DEBUG" que publicó Harper Shelby. Obviamente dependiendo del entorno (win/linux / etc.) el código podría necesitar ser ajustado un poco.

Yo estaba en el pasado usando el "si DEBUG", pero encontré que de vez en cuando necesitaba hacer pruebas con DEUBG establecido en False. Lo que realmente quería distinguir si el entorno era producción o desarrollo, lo que me dio la libertad de elegir el nivel de DEPURACIÓN.

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'

Todavía considere esta forma de configuración un trabajo en progreso. No he visto ninguna manera de manejar la configuración de Django que cubriera todas las bases y al mismo tiempo no fuera una molestia total para configurar (no estoy abajo con los métodos de archivos de configuración 5x).

 19
Author: T. Stone,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-26 18:47:16

Utilizo un settings_local.py y a settings_production.py. Después de probar varias opciones he encontrado que es fácil perder el tiempo con soluciones complejas cuando simplemente tener dos archivos de configuración se siente fácil y rápido.

Cuando utiliza mod_python/mod_wsgi para su proyecto Django, debe apuntar a su archivo de configuración. Si lo apuntas a app/settings_local.py en su servidor local y app/settings_production.py en su servidor de producción, la vida se vuelve fácil. Solo tienes que editar el archivo de configuración y reinicie el servidor (Django development server se reiniciará automáticamente).

 14
Author: Kai,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-26 18:12:30

Administro mis configuraciones con la ayuda de django-split-settings.

Es un reemplazo desplegable para la configuración predeterminada. Es simple, pero configurable. Y la refactorización de la configuración existente no es necesaria.

Aquí hay un pequeño ejemplo (archivo 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()
    )

Eso es todo.

Actualizar

Escribí una entrada de blog sobre cómo administrar la configuración de django con django-split-sttings. ¡Echa un vistazo!

 7
Author: sobolevn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-08 10:31:27

El problema con la mayoría de estas soluciones es que tiene sus configuraciones locales aplicadas antes de las comunes, o después de.

Así que es imposible anular cosas como

  • la configuración específica de env define las direcciones para el grupo memcached, y en el archivo de configuración principal este valor se usa para configurar el backend de caché
  • la configuración específica de env agrega o elimina aplicaciones / middleware a la predeterminada

En el a la misma hora.

Se puede implementar una solución usando archivos de configuración de estilo "ini"con la clase ConfigParser. Admite varios archivos, interpolación de cadenas perezosas, valores predeterminados y muchas otras ventajas. Una vez que se han cargado varios archivos, se pueden cargar más archivos y sus valores anularán los anteriores, si los hay.

Carga uno o más archivos de configuración, dependiendo de la dirección de la máquina, variables de entorno e incluso valores en archivos de configuración previamente cargados. Entonces solo tiene que utilizar los valores analizados para completar la configuración.

Una estrategia que he utilizado con éxito ha sido:

  • Cargar un archivo predeterminado defaults.ini
  • Compruebe el nombre de la máquina y cargue todos los archivos que coincidan con el FQDN invertido, desde la coincidencia más corta hasta la más larga (por lo tanto, cargué net.ini, luego net.domain.ini, luego net.domain.webserver01.ini, cada uno posiblemente anulando los valores del anterior). Esta cuenta también para las máquinas de los desarrolladores, por lo que cada uno podría configurar su controlador de base de datos preferido, sucesivamente. para el desarrollo local
  • Compruebe si hay un" nombre de clúster " declarado, y en ese caso load cluster.cluster_name.ini, que puede definir cosas como IPS de base de datos y caché

Como ejemplo de algo que puede lograr con esto, puede definir un valor de "subdominio" por env, que luego se usa en la configuración predeterminada (como hostname: %(subdomain).whatever.net) para definir todos los nombres de host necesarios y las cosas de cookies que django necesita para funcionar.

Esto es lo más SECO que pude conseguir, la mayoría de los archivos (existentes) tenían solo 3 o 4 configuración. Además de esto tuve que administrar la configuración del cliente, por lo que existía un conjunto adicional de archivos de configuración (con cosas como nombres de base de datos, usuarios y contraseñas, subdominio asignado, etc.), uno o más por cliente.

Uno puede escalar esto tan bajo o tan alto como sea necesario, simplemente ponga en el archivo de configuración las claves que desea configurar por entorno, y una vez que haya necesidad de una nueva configuración, ponga el valor anterior en la configuración predeterminada, y lo anule donde necesario.

Este sistema ha demostrado ser fiable y funciona bien con el control de versiones. Se ha utilizado durante mucho tiempo administrando dos clústeres de aplicaciones separados (15 o más instancias separadas del sitio de django por máquina), con más de 50 clientes, donde los clústeres cambiaban de tamaño y miembros dependiendo del estado de ánimo del administrador del sistema...

 6
Author: rewritten,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-01 14:18:02

Recuerde que settings.py es un archivo de código en vivo. Suponiendo que no tiene establecido un sistema de DEPURACIÓN en producción (lo cual es una práctica recomendada), puede hacer algo como:

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

Bastante básico, pero usted podría, en teoría, subir a cualquier nivel de complejidad basado solo en el valor de DEPURACIÓN - o cualquier otra variable o verificación de código que desee utilizar.

 4
Author: Harper Shelby,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-26 18:05:19

También estoy trabajando con Laravel y me gusta la implementación allí. Traté de imitarlo y combinarlo con la solución propuesta por T. Stone (ver arriba):

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

Tal vez algo como esto te ayudaría.

 4
Author: Robert Kuzma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-04 08:38:05

Mi solución a ese problema es también una mezcla de algunas soluciones ya mencionadas aquí:

  • Guardo un archivo llamado local_settings.py que tiene el contenido USING_LOCAL = True en dev y USING_LOCAL = False en prod
  • En settings.py hago una importación de ese archivo para obtener la configuración USING_LOCAL

Entonces baso todas mis configuraciones dependientes del entorno en esa:

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

Prefiero esto a tener dos separados settings.py archivos que necesito mantener ya que puedo mantener mi configuración estructurada en un solo archivo más fácil que tenerlos repartidos en varios archivos. Así, cuando actualizo una configuración no me olvido de hacerlo para ambos entornos.

Por supuesto que cada método tiene sus desventajas y este no es una excepción. El problema aquí es que no puedo sobrescribir el archivo local_settings.py cada vez que introduzco mis cambios en producción, lo que significa que no puedo copiar todos los archivos a ciegas, pero eso es algo con lo que puedo vivir.

 3
Author: Miguel Ventura,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-26 20:10:27

Para la mayoría de mis proyectos utilizo el siguiente patrón:

  1. Crear settings_base.py donde almaceno configuraciones que son comunes para todos los entornos
  2. Cada vez que necesito usar un nuevo entorno con requisitos específicos, creo un nuevo archivo de configuración (p. ej. settings_local.py) que hereda el contenido de settings_base.py y anula / agrega variables de configuración adecuadas (from settings_base import *)

(Para ejecutar manage.py con el archivo de configuración personalizado, simplemente use la opción de comando settings settings: manage.py <command> --settings=settings_you_wish_to_use.py)

 3
Author: dzida,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-03 09:53:07

Utilizo una variación de lo que jpartogi mencionó anteriormente, que encuentro un poco más corta:

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 __name__ == "__main__":
  execute_manager(settings)

Básicamente en cada equipo (desarrollo o producción) tengo el adecuado hostname_settings.py archivo que se carga dinámicamente.

 3
Author: stratosgear,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-06 19:48:52

También hay Ajustes de Django Classy. Personalmente soy un gran fan de ella. Está construido por una de las personas más activas en el IRC de Django. Usarías var del entorno para establecer las cosas.

Http://django-classy-settings.readthedocs.io/en/latest /

 3
Author: Emett Speer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-21 17:56:20

TL;DR: El truco es modificar os.environment antes de importar settings/base.py en cualquier settings/<purpose>.py, esto simplificará mucho las cosas.


Solo pensar en todos estos archivos entrelazados me da dolor de cabeza. Combinar, importar (a veces condicionalmente), sobreescribir, parchear lo que ya estaba establecido en caso de que DEBUG la configuración cambiara más adelante. Qué pesadilla!

A través de los años pasé por todas las soluciones diferentes. Todos de alguna manera funcionan, pero son tan dolorosos de manejar. ¡WTF! ¿Realmente necesitamos toda esa molestia? Empezamos con un solo archivo settings.py. Ahora necesitamos una documentación solo para combinar correctamente todos estos juntos en un orden correcto!

Espero finalmente llegar al (mi) punto dulce con la solución a continuación.

Recapitulemos las metas (algunas comunes, otras mías) {[46]]}
  1. Mantenga los secretos en secreto, no los almacene en un repositorio.

  2. Establecer / leer claves y secretos a través de la configuración del entorno, 12 factor style .

  3. Tener valores predeterminados de reserva sensatos. Lo ideal para el desarrollo local no necesita nada más aparte de los valores predeterminados.

  4. ...pero trate de mantener la producción predeterminada segura. Es mejor omitir una anulación de configuración localmente, que tener que recordar para ajustar la configuración por defecto seguro para la producción.

  5. Tener la capacidad de cambiar DEBUG on/off de una manera que puede tener un efecto en otros ajustes (por ejemplo. usando javascript comprimido o ni).

  6. Cambiar entre configuraciones de propósito, como local / testing/staging / production, debe basarse solo en DJANGO_SETTINGS_MODULE, nada más.

  7. ...pero permitir más parametrización a través de ajustes de entorno como DATABASE_URL.

  8. ...también les permiten utilizar diferentes configuraciones de propósito y ejecutarlos localmente uno al lado del otro, por ejemplo. configuración de producción en la máquina de desarrollo local, para acceder a la base de datos de producción o al estilo comprimido de prueba de humo hoja.

  9. Fail si una variable de entorno no se establece explícitamente (requiere un valor vacío como mínimo), especialmente en producción, por ejemplo. EMAIL_HOST_PASSWORD.

  10. Responder al valor predeterminado DJANGO_SETTINGS_MODULE establecido en manage.py durante django-admin startproject

  11. Mantenga los condicionales al mínimo, si la condición es el tipo de entorno propuesto (eg. para el archivo de registro del conjunto de producción y su rotación), anule los ajustes en los ajustes propuestos asociados file.

No es{[46]]}
  1. No permita que django lea la configuración DJANGO_SETTINGS_MODULE de un archivo.
    Ugh! Piensa en lo meta que es esto. Si necesita tener un archivo (como docker env) lea eso en el entorno antes de mirar un proceso de django.

  2. No anule DJANGO_SETTINGS_MODULE en el código de su proyecto / aplicación, por ejemplo. basado en nombre de host o nombre de proceso.
    Si usted es perezoso para establecer variable de entorno (como para setup.py test) hacerlo en herramientas justo antes de ejecutar el código del proyecto.

  3. Evite la magia y los parches de cómo django lee sus ajustes, preprocese los ajustes pero no interfiera después.

  4. No hay lógica complicada basada en tonterías. La configuración debe ser fija y materializada, no computada sobre la marcha. Proporcionar un valor predeterminado de reserva es suficiente lógica aquí.
    ¿Realmente desea depurar, por qué localmente tiene un conjunto correcto de configuraciones pero en producción en un servidor remoto, en una de cien máquinas, ¿algo calculado de manera diferente? Oh! ¿Pruebas unitarias? ¿Para ajustes? ¿En serio?

Solución

Mi estrategia consiste en un excelente django-environ usado con archivos de estilo ini , proporcionar os.environment valores predeterminados para el desarrollo local, algunos archivos settings/<purpose>.py mínimos y cortos que tienen un import settings/base.py DESPUÉS de el os.environment se estableció a partir de un archivo INI. Esto efectivamente nos da una especie de inyección de configuración.

El truco aquí es modifique os.environment antes de importar settings/base.py.

Para ver el ejemplo completo ve a hacer el repo: https://github.com/wooyek/django-settings-strategy

.
│   manage.py
├───data
└───website
    ├───settings
    │   │   __init__.py   <-- imports local for compatybility
    │   │   base.py       <-- almost all the settings, reads from proces environment 
    │   │   local.py      <-- a few modifications for local development
    │   │   production.py <-- ideally is empy and everything is in base 
    │   │   testing.py    <-- mimics production with a reasonable exeptions
    │   │   .env          <-- for local use, not kept in repo
    │   __init__.py
    │   urls.py
    │   wsgi.py

Ajustes/.env

A por defecto para el desarrollo local. Un archivo secreto, para establecer principalmente las variables de entorno requeridas. Establézcalos en valores vacíos si no son necesarios en el desarrollo local. Proporcionamos valores predeterminados aquí y no en settings/base.py para fallar en cualquier otra máquina si faltan en el ambiente.

Settings/local.py

Lo que sucede aquí, es cargar el entorno desde settings/.env, luego importar la configuración común de settings/base.py. Después de eso podemos anular algunos para facilitar el desarrollo local.

import logging
import environ

logging.debug("Settings loading: %s" % __file__)

# This will read missing environment variables from a file
# We wan to do this before loading a base settings as they may depend on environment
environ.Env.read_env(DEBUG='True')

from .base import *

ALLOWED_HOSTS += [
    '127.0.0.1',
    'localhost',
    '.example.com',
    'vagrant',
    ]

# https://docs.djangoproject.com/en/1.6/topics/email/#console-backend
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
# EMAIL_BACKEND = 'django.core.mail.backends.dummy.EmailBackend'

LOGGING['handlers']['mail_admins']['email_backend'] = 'django.core.mail.backends.dummy.EmailBackend'

# Sync task testing
# http://docs.celeryproject.org/en/2.5/configuration.html?highlight=celery_always_eager#celery-always-eager

CELERY_ALWAYS_EAGER = True
CELERY_EAGER_PROPAGATES_EXCEPTIONS = True

Settings/production.py

Para la producción no debemos esperar un archivo de entorno, pero es más fácil tener uno si estamos probando algo. Pero de todos modos, lest proporciona pocos valores predeterminados en línea, por lo que settings/base.py puede responder en consecuencia.

environ.Env.read_env(Path(__file__) / "production.env", DEBUG='False', ASSETS_DEBUG='False')
from .base import *

El principal punto de interés aquí son DEBUG y ASSETS_DEBUG reemplaza, se aplicarán a python os.environ SOLO si faltan en el entorno y en el archivo.

Estos serán nuestros valores predeterminados de producción, no es necesario ponerlos en el entorno o archivo, pero se pueden sobrescribir si es necesario. ¡Genial!

Settings/base.py

Estos son los ajustes de django en su mayoría vanilla, con algunos condicionales y mucho de leerlos desde el entorno. Casi todo está aquí, manteniendo todos los entornos propuestos consistentes y lo más similares posible.

Las principales diferencias están a continuación (espero que sean auto explicativas):

import environ

# https://github.com/joke2k/django-environ
env = environ.Env()

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

# Where BASE_DIR is a django source root, ROOT_DIR is a whole project root
# It may differ BASE_DIR for eg. when your django project code is in `src` folder
# This may help to separate python modules and *django apps* from other stuff
# like documentation, fixtures, docker settings
ROOT_DIR = BASE_DIR

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = env('SECRET_KEY')

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = env('DEBUG', default=False)

INTERNAL_IPS = [
    '127.0.0.1',
]

ALLOWED_HOSTS = []

if 'ALLOWED_HOSTS' in os.environ:
    hosts = os.environ['ALLOWED_HOSTS'].split(" ")
    BASE_URL = "https://" + hosts[0]
    for host in hosts:
        host = host.strip()
        if host:
            ALLOWED_HOSTS.append(host)

SECURE_SSL_REDIRECT = env.bool('SECURE_SSL_REDIRECT', default=False)

# Database
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases

if "DATABASE_URL" in os.environ:  # pragma: no cover
    # Enable database config through environment
    DATABASES = {
        # Raises ImproperlyConfigured exception if DATABASE_URL not in os.environ
        'default': env.db(),
    }

    # Make sure we use have all settings we need
    # DATABASES['default']['ENGINE'] = 'django.contrib.gis.db.backends.postgis'
    DATABASES['default']['TEST'] = {'NAME': os.environ.get("DATABASE_TEST_NAME", None)}
    DATABASES['default']['OPTIONS'] = {
        'options': '-c search_path=gis,public,pg_catalog',
        'sslmode': 'require',
    }
else:
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            # 'ENGINE': 'django.contrib.gis.db.backends.spatialite',
            'NAME': os.path.join(ROOT_DIR, 'data', 'db.dev.sqlite3'),
            'TEST': {
                'NAME': os.path.join(ROOT_DIR, 'data', 'db.test.sqlite3'),
            }
        }
    }

STATIC_ROOT = os.path.join(ROOT_DIR, 'static')

# django-assets
# http://django-assets.readthedocs.org/en/latest/settings.html

ASSETS_LOAD_PATH = STATIC_ROOT
ASSETS_ROOT = os.path.join(ROOT_DIR, 'assets', "compressed")
ASSETS_DEBUG = env('ASSETS_DEBUG', default=DEBUG)  # Disable when testing compressed file in DEBUG mode
if ASSETS_DEBUG:
    ASSETS_URL = STATIC_URL
    ASSETS_MANIFEST = "json:{}".format(os.path.join(ASSETS_ROOT, "manifest.json"))
else:
    ASSETS_URL = STATIC_URL + "assets/compressed/"
    ASSETS_MANIFEST = "json:{}".format(os.path.join(STATIC_ROOT, 'assets', "compressed", "manifest.json"))
ASSETS_AUTO_BUILD = ASSETS_DEBUG
ASSETS_MODULES = ('website.assets',)

El último bit muestra el poder aquí. ASSETS_DEBUG tiene un defecto sensible, que puede ser anulado en settings/production.py e incluso que puede ser anulado por una configuración de entorno! Yay!

En efecto, tenemos una jerarquía mixta de importancia:

  1. settings/.py -establece los valores predeterminados basados en el propósito, no almacena secretos
  2. settings/base.py - está controlado principalmente por el medio ambiente
  3. configuración del entorno de proceso-12 factor baby!
  4. ajustes/.env - valores predeterminados locales para easy startup
 3
Author: Janusz Skonieczny,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-15 11:45:33

Lo diferencio en manage.py y creó dos archivos de configuración separados: local_settings.py y prod_settings.py.

En manage.py Compruebo si el servidor es un servidor local o un servidor de producción. Si es un servidor local se cargaría local_settings.py y es un servidor de producción que cargaría prod_settings.py. Básicamente así es como se vería:

#!/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 __name__ == "__main__":
    execute_manager(settings)

Me pareció más fácil separar el archivo de configuración en dos archivos separados en lugar de hacer un montón de ifs dentro del archivo de configuración.

 1
Author: Joshua Partogi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-27 11:52:22

Como alternativa para mantener un archivo diferente si: Si está utilizando git o cualquier otro VCS para enviar códigos desde el local al servidor, lo que puede hacer es agregar el archivo de configuración .gitignore.

Esto te permitirá tener contenido diferente en ambos lugares sin ningún problema. Así que en el servidor se puede configurar una versión independiente de settings.py y cualquier cambio realizado en el local no se reflejará en el servidor y viceversa.

Además, eliminará la settings.py archivo desde github también, la gran culpa, que he visto muchos novatos haciendo.

 1
Author: sprksh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-03 06:15:30

Para usar una configuración settings diferente en un entorno diferente, cree un archivo de configuración diferente. Y en el script de implementación, inicie el servidor usando --settings=<my-settings.py> parámetro, a través del cual puede usar diferentes ajustes en diferentes entornos.

Beneficios de usar este enfoque :

  1. La configuración será modular en función de cada entorno

  2. Puede importar el master_settings.py que contiene la configuración base en el environmnet_configuration.py y reemplazar los valores que desea cambiar en ese entorno.

  3. Si tiene un equipo enorme, cada desarrollador puede tener su propio local_settings.py que puede agregar al repositorio de código sin ningún riesgo de modificar la configuración del servidor. Puede agregar estas configuraciones locales a .gitnoresi usa git o .hginoresi Mercurialpara Control de versiones (o cualquier otro). De esa manera, la configuración local ni siquiera será la parte de la base de código real manteniéndola limpiar.

 1
Author: Moinuddin Quadri,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-09 22:40:13

1 - Crear una nueva carpeta dentro de la aplicación y la configuración de nombre a la misma.

2-Ahora cree un nuevo archivo init.py en él y dentro de él escriba

    from .base import *

    try:

De .importación local *

    except:

Pass

     try:

De .producción importación *

     except:

Pass

3-Crear tres nuevos archivos en la carpeta de configuración nombre local.py y production.py y base.py

4-Dentro base.py copia todo el contenido de la configuración anterior.p carpeta y cambiarle el nombre con algo diferente digamos old_settings.py

5-In base.py cambie su ruta BASE_DIR para que apunte a su nueva ruta de configuración

Old path-> BASE_DIR = os.camino.dirname (os.camino.dirname (os.camino.archivo abspath ()))

Nueva ruta -> BASE_DIR = os.camino.dirname (os.camino.dirname (os.camino.dirname (os.camino.archivo abspath ()))

Ahora de esta manera el dir del proyecto puede ser estructurado y manejable entre la producción y el desarrollo local.

 1
Author: Jack Ryan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-10 04:32:50

Tuve mi configuración dividida de la siguiente manera

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

Tenemos 3 ambientes

  • dev
  • estadificación
  • producción

Ahora, obviamente, la puesta en escena y la producción deben tener el máximo entorno similar posible. Así que nos quedamos prod.py para ambos.

Pero hubo un caso en el que tuve que identificar que el servidor en ejecución es un servidor de producción. La respuesta de @T. Stone me ayudó a escribir el cheque de la siguiente manera.

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
Author: Kishor Pawar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-12 16:39:47

Encontré las respuestas aquí muy útiles. (¿ Se ha resuelto esto de manera más definitiva? La última respuesta fue hace un año. Después de considerar todos los enfoques enumerados, se me ocurrió una solución que no vi en la lista aquí.

Mis criterios fueron:

  • Todo debe estar en control de código fuente. No me gustan las cosas raras por ahí.
  • Idealmente, mantenga la configuración en un archivo. Me olvido de las cosas si no estoy mirando a la derecha en ellos:)
  • No hay ediciones manuales para desplegar. Debería ser capaz de probar / empujar / desplegar con un solo comando fabric.
  • Evite filtrar los ajustes de desarrollo a la producción.
  • Manténgase lo más cerca posible del diseño "estándar" (*tos*) de Django como sea posible.

Pensé que encender la máquina host tenía algún sentido, pero luego pensé que el verdadero problema aquí es diferentes configuraciones para diferentes entornos , y tuve un momento ajá. Puse este código al final de mi settings.py archivo:

try:
    os.environ['DJANGO_DEVELOPMENT_SERVER'] # throws error if unset
    DEBUG = True
    TEMPLATE_DEBUG = True
    # This is naive but possible. Could also redeclare full app set to control ordering. 
    # Note that it requires a list rather than the generated tuple.
    INSTALLED_APPS.extend([
        'debug_toolbar',
        'django_nose',
    ])
    # Production database settings, alternate static/media paths, etc...
except KeyError: 
    print 'DJANGO_DEVELOPMENT_SERVER environment var not set; using production settings'

De esta manera, la aplicación establece por defecto la configuración de producción, lo que significa que está explícitamente "en la lista blanca" de su entorno de desarrollo. Es mucho más seguro olvidarse de establecer la variable de entorno localmente que si fuera al revés y se olvidara de establecer algo en producción y dejar que se usen algunas configuraciones de desarrollo.

Cuando se desarrolla localmente, ya sea desde el shell o en a .bash_profile o donde sea:

$ export DJANGO_DEVELOPMENT_SERVER=yep

(O si está desarrollando en Windows, configure a través del Panel de Control o como se llame en estos días... Windows siempre lo hacía tan oscuro que se podían establecer variables de entorno.)

Con este enfoque, los ajustes de desarrollo están todos en un lugar (estándar), y simplemente anulan los de producción donde sea necesario. Cualquier error con los ajustes de desarrollo debe ser completamente seguro para comprometerse con el control de la fuente sin impacto en la producción.

 -3
Author: Jason Boyd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-17 06:49:49