Estructura de configuración#
Organización de configuraciones de Django para diferentes entornos.
Descripción general#
Construbot utiliza configuraciones basadas en el entorno con herencia para evitar la duplicación y admitir múltiples entornos.
Ubicación: construbot/config/settings/
Archivos:
base.py- Configuración compartida para todos los entornoslocal.py- Configuración de desarrollotest.py- Configuración de pruebaproducción.py- Configuración de producción
Jerarquía de configuración#
base.py (Common settings)
├── local.py (Development)
├── test.py (Testing)
└── production.py (Production)
Todos los archivos de entorno se importan desde base.py:
# local.py, test.py, production.py
from .base import * # Import all base settings
from .base import env # Import environ instance
# Override specific settings
DEBUG = True
ALLOWED_HOSTS = ['localhost', '127.0.0.1']
Configuración básica (base.py)#
Configuraciones comunes compartidas en todos los entornos:
Núcleo de Django:
# Django version
DJANGO_ADMIN_URL = env('DJANGO_ADMIN_URL', default='admin/')
# Internationalization
LANGUAGE_CODE = 'es-mx'
TIME_ZONE = 'America/Mexico_City'
USE_I18N = True
USE_L10N = True
USE_TZ = True
Aplicaciones instaladas:
INSTALLED_APPS = [
# AutocompleteLight MUST be before admin
'dal',
'dal_select2',
# Django contrib
'django.contrib.admin',
'django.contrib.auth',
...
# Third-party
'rest_framework',
'rest_framework.authtoken',
'allauth',
'allauth.account',
...
# Local apps
'construbot.users',
'construbot.proyectos',
'construbot.api',
'construbot.core',
]
Advertencia
dal y dal_select2 DEBEN aparecer antes de django.contrib.admin o los widgets de autocompletar no funcionarán.
Middleware:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware', # Static files
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
Autenticación:
AUTH_USER_MODEL = 'users.User' # Custom user model
AUTHENTICATION_BACKENDS = [
'construbot.core.backends.ModelBackend', # Custom backend
'allauth.account.auth_backends.AuthenticationBackend',
]
Base de datos (usa DATABASE_URL):
DATABASES = {
'default': env.db('DATABASE_URL'),
}
DATABASES['default']['ATOMIC_REQUESTS'] = True
Archivos estáticos/multimedia:
STATIC_ROOT = str(ROOT_DIR / 'staticfiles')
STATIC_URL = '/static/'
STATICFILES_DIRS = [str(APPS_DIR / 'static')]
MEDIA_ROOT = str(APPS_DIR / 'media')
MEDIA_URL = '/media/'
Hashhers de contraseña:
PASSWORD_HASHERS = [
'django.contrib.auth.hashers.Argon2PasswordHasher', # Primary
'django.contrib.auth.hashers.PBKDF2PasswordHasher',
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
]
Apio:
if USE_TZ:
CELERY_TIMEZONE = TIME_ZONE
CELERY_BROKER_URL = env('CELERY_BROKER_URL', default=env('REDIS_URL', default='redis://localhost:6379/0'))
CELERY_RESULT_BACKEND = CELERY_BROKER_URL
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TASK_TIME_LIMIT = 5 * 60 # 5 minutes
CELERY_TASK_SOFT_TIME_LIMIT = 60 # 1 minute
Configuración local (local.py)#
Configuración del entorno de desarrollo:
Modo de depuración:
DEBUG = True
Anfitriones permitidos:
ALLOWED_HOSTS = ['localhost', '0.0.0.0', '127.0.0.1']
Base de datos:
Puede usar variables de entorno o valores predeterminados en PostgreSQL local:
DATABASES = {
'default': env.db('DATABASE_URL', default='postgresql://debug:debug@postgres:5432/construbot')
}
Almacenamiento en caché (desarrollo - caché ficticio):
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': '',
}
}
Correo electrónico (backend de la consola):
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
EMAIL_HOST = 'localhost'
EMAIL_PORT = 1025 # MailHog
Herramientas de depuración:
INSTALLED_APPS += ['debug_toolbar']
MIDDLEWARE += ['debug_toolbar.middleware.DebugToolbarMiddleware']
INTERNAL_IPS = ['127.0.0.1', '10.0.2.2']
extensiones-django:
INSTALLED_APPS += ['django_extensions']
Configuración de prueba (test.py)#
Configuración del entorno de prueba:
Depuración desactivada:
DEBUG = False
Base de datos (SQLite en memoria):
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': ':memory:',
}
}
Hash rápido de contraseñas:
PASSWORD_HASHERS = [
'django.contrib.auth.hashers.MD5PasswordHasher',
]
Plantillas (sin almacenamiento en caché):
TEMPLATES[0]['OPTIONS']['loaders'] = [
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
]
Correo electrónico (backend de memoria):
EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
Apio (ejecución sincrónica):
CELERY_TASK_ALWAYS_EAGER = True
CELERY_TASK_EAGER_PROPAGATES = True
Configuración de producción (producción.py)#
Configuración del entorno de producción:
Depuración desactivada:
DEBUG = env.bool('DJANGO_DEBUG', False)
Anfitriones permitidos:
ALLOWED_HOSTS = env.list('DJANGO_ALLOWED_HOSTS', default=['example.com'])
Seguridad:
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SECURE_SSL_REDIRECT = env.bool('DJANGO_SECURE_SSL_REDIRECT', default=True)
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_CONTENT_TYPE_NOSNIFF = True
Base de datos:
DATABASES['default'] = env.db('DATABASE_URL')
DATABASES['default']['ATOMIC_REQUESTS'] = True
DATABASES['default']['CONN_MAX_AGE'] = env.int('CONN_MAX_AGE', default=60)
Almacenamiento en caché (Redis):
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': env('REDIS_URL'),
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
'IGNORE_EXCEPTIONS': True,
}
}
}
Archivos estáticos (WhiteNoise):
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
Archivos multimedia (S3):
if env.bool('USE_S3', default=False):
AWS_ACCESS_KEY_ID = env('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = env('AWS_SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = env('AWS_STORAGE_BUCKET_NAME')
AWS_S3_REGION_NAME = env('AWS_S3_REGION_NAME', default='us-east-1')
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
Correo electrónico (servicio de producción):
EMAIL_BACKEND = env('DJANGO_EMAIL_BACKEND', default='anymail.backends.mailgun.EmailBackend')
Explotación florestal:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
},
},
'handlers': {
'console': {
'level': 'INFO',
'class': 'logging.StreamHandler',
'formatter': 'verbose'
},
},
'root': {
'level': 'INFO',
'handlers': ['console'],
},
}
Centinela:
if env('SENTRY_DSN', default=None):
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration
sentry_sdk.init(
dsn=env('SENTRY_DSN'),
integrations=[DjangoIntegration()],
environment=env('SENTRY_ENVIRONMENT', default='production'),
)
Selección del entorno#
A través de variable de entorno:
export DJANGO_SETTINGS_MODULE=construbot.config.settings.production
python manage.py runserver
A través de Makefile:
make dev # Uses local settings
make buildprod # Uses production settings
make test # Uses test settings
En administrar.py:
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'construbot.config.settings.local')
entorno-django#
Cargando archivo .env:
# In base.py
import environ
ROOT_DIR = Path(__file__).resolve(strict=True).parent.parent.parent
APPS_DIR = ROOT_DIR / 'construbot'
env = environ.Env()
# Read .env file
READ_DOT_ENV_FILE = env.bool('DJANGO_READ_DOT_ENV_FILE', default=False)
if READ_DOT_ENV_FILE:
env.read_env(str(ROOT_DIR / '.env'))
Acceso a variables:
DEBUG = env.bool('DJANGO_DEBUG', default=False)
SECRET_KEY = env('DJANGO_SECRET_KEY')
DATABASE_URL = env.db('DATABASE_URL')
ALLOWED_HOSTS = env.list('DJANGO_ALLOWED_HOSTS', default=[])
Modo biblioteca#
Configuración CONSTRUBOT_AS_LIBRARY:
Cuando es True, desactiva las funciones independientes:
# In base.py
CONSTRUBOT_AS_LIBRARY = env.bool('CONSTRUBOT_AS_LIBRARY', default=False)
if not CONSTRUBOT_AS_LIBRARY:
INSTALLED_APPS += [
'construbot.account_config', # Only in standalone mode
]
Afecta:
Disponibilidad de la interfaz de administración
URL de administración de cuentas
Sistema de autenticación
Consulte Modo biblioteca para obtener más detalles.
Mejores prácticas#
1. Nunca cometas secretos:
# Use environment variables
SECRET_KEY = env('DJANGO_SECRET_KEY')
# Never hardcode:
# SECRET_KEY = 'abc123' # BAD!
2. Utilice valores predeterminados sensatos:
DEBUG = env.bool('DJANGO_DEBUG', default=False) # Safe default
3. Variables requeridas del documento:
Cree .env.example con todas las variables requeridas.
4. Validar configuración de producción:
python manage.py check --deploy
5. Mantenga base.py SECO:
Coloque configuraciones comunes en base.py, anule solo lo que difiera.
Solución de problemas#
Módulo de configuración incorrecto cargado:
# Check current settings
python manage.py diffsettings
# Verify environment variable
echo $DJANGO_SETTINGS_MODULE
La configuración no se carga desde .env:
# Ensure this is set
export DJANGO_READ_DOT_ENV_FILE=True
# Or in .env file itself (chicken-egg problem)
# Better: export it before running Django
Errores de importación:
# Always import from base
from .base import *
from .base import env # Don't forget this!
Ver también#
Descripción general - Architecture overview
Configuración - Environment configuration
Variables de entorno - Production variables