Preparación de aplicación Django

Módulo: django

Taller Digital

Ficha del módulo

  • ID: django-preparacion-app
  • Categoría: django

Preparación de aplicación Django

🎯 Objetivo: preparar una aplicación Django para despliegue y carga a servidor.

Estructura requerida

El proyecto Django debe tener la siguiente estructura. Los tres primeros archivos se crearán en los pasos siguientes.

proyecto/
├── Procfile ver paso siguiente
├── runtime.txt ver paso siguiente
├── requirements.txt ver paso siguiente
│── manage.py
│── proyecto/
   ├── settings/
   ├── base.py
   ├── development.py
   └── production.py
   ├── wsgi.py / asgi.py
   ├── urls.py
└── apps/

Crear archivo Procfile

El archivo Procfile establece cómo se debe ejecutar la aplicación en Dokku. No debe llevar ninguna extensión de archivo. Dentro se pueden definir uno o más servicios y acciones a ejecutar en cada despliegue (release).

web: gunicorn proyecto.wsgi:application --bind 0.0.0.0:$PORT --workers 3 --timeout 60
release: python manage.py migrate --noinput && python manage.py collectstatic --noinput

Breve explicación:

Crear archivo runtime.txt

El archivo runtime.txt contiene la versión de Python que se debe utilizar en Dokku para la aplicación. Ajustar versión según sea necesario.

python-3.11.9

Para ver las versiones soportadas, visitar Heroku Python Supported Runtimes.

Crear archivo requirements.txt

El archivo requirements.txt contiene las dependencias de la aplicación.

Para crear el archivo por primera vez, utilizar el siguiente comando:

# dentro del entorno virtual del proyecto
pip freeze > requirements.txt

Luego, editar el archivo para agregar las dependencias de producción.

# para producción
gunicorn==21.2.0
psycopg2-binary==2.9.9
whitenoise==6.6.0
django-environ==0.11.2
dj-database-url==2.1.0

Archivos settings por entorno

El archivo settings.py contiene la configuración base de la aplicación. Este archivo puede ser desglosado en archivos por entorno, como base.py, development.py y production.py.

Por defecto, un proyecto de Django solamente incluye un archivo settings.py. Para crear los archivos por entorno, crear una carpeta settings dentro del proyecto e incluir los archivos base.py, development.py y production.py con los siguientes contenidos:

settings/base.py

from pathlib import Path
import environ

BASE_DIR = Path(__file__).resolve().parent.parent.parent

env = environ.Env()

SECRET_KEY = env("SECRET_KEY", default="dev-insecure-key")
DEBUG = False

ALLOWED_HOSTS = []

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",

    # apps propias
    # "apps.core",
]

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "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",
]

ROOT_URLCONF = "config.urls"

TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [BASE_DIR / "templates"],
        "APP_DIRS": True,
        "OPTIONS": {
            "context_processors": [
                "django.template.context_processors.request",
                "django.contrib.auth.context_processors.auth",
                "django.contrib.messages.context_processors.messages",
            ],
        },
    }
]

WSGI_APPLICATION = "config.wsgi.application"

LANGUAGE_CODE = "es-cl"
TIME_ZONE = "America/Santiago"
USE_I18N = True
USE_TZ = True

STATIC_URL = "/static/"
STATIC_ROOT = BASE_DIR / "staticfiles"

MEDIA_URL = "/media/"
MEDIA_ROOT = BASE_DIR / "media"

DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"

settings/development.py

from .base import *

DEBUG = True

ALLOWED_HOSTS = ["localhost", "127.0.0.1", "0.0.0.0"]

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.sqlite3",
        "NAME": BASE_DIR / "db.sqlite3",
    }
}

INSTALLED_APPS += [
    # "debug_toolbar",
]

MIDDLEWARE += [
    # "debug_toolbar.middleware.DebugToolbarMiddleware",
]

INTERNAL_IPS = ["127.0.0.1"]

settings/production.py

from .base import *

import dj_database_url

SECRET_KEY = env("SECRET_KEY")
DEBUG = env.bool("DEBUG", default=False)

ALLOWED_HOSTS = env.list("ALLOWED_HOSTS")

CSRF_TRUSTED_ORIGINS = env.list(
    "CSRF_TRUSTED_ORIGINS",
    default=[]
)

DATABASES = {
    "default": dj_database_url.config(
        default=env("DATABASE_URL"),
        conn_max_age=600,
        ssl_require=env.bool("DB_SSL_REQUIRE", default=False),
    )
}

MIDDLEWARE.insert(
    1,
    "whitenoise.middleware.WhiteNoiseMiddleware"
)

STATIC_URL = "/static/"
STATIC_ROOT = BASE_DIR / "staticfiles"
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"

SECURE_SSL_REDIRECT = env.bool("SECURE_SSL_REDIRECT", default=True)

SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

SECURE_HSTS_SECONDS = env.int("SECURE_HSTS_SECONDS", default=31536000)
SECURE_HSTS_INCLUDE_SUBDOMAINS = env.bool("SECURE_HSTS_INCLUDE_SUBDOMAINS", default=True)
SECURE_HSTS_PRELOAD = env.bool("SECURE_HSTS_PRELOAD", default=True)

X_FRAME_OPTIONS = "DENY"
SECURE_CONTENT_TYPE_NOSNIFF = True
SECURE_REFERRER_POLICY = "same-origin"

USE_X_FORWARDED_HOST = True
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")

Modificar según sea necesario.