ENbext.dev
DocumentationIntégrations de frameworks

Traduction automatique depuis l’anglais. Consulter l’original.

Sur cette page

Intégration Django

bext présente Django comme un proxy inverse. Django conserve chaque élément de sa propre pile (ORM, admin, formulaires, middleware, commandes de gestion) et bext gère TLS, HTTP/2, HTTP/3, le WAF, la mise en cache et la livraison de fichiers statiques. L'amont est un processus Gunicorn ou Uvicorn régulier écoutant sur 127.0.0.1 ; bext n'exécute jamais Python en cours de processus.

Architecture#

code
client ──TLS──▶ bext edge ──HTTP/1.1──▶ Gunicorn / Uvicorn ──▶ Django
                │                              │
                │  serves /static/**           │
                │  serves /media/**            │
                │  WAF, cache, tracing         │
                │  HTTP/2, HTTP/3              │
                └── upstream health checks ────┘

Tout ce qui se trouve après la limite amont est du stock Django. Tout avant est en stock bext. Les deux se rencontrent via localhost HTTP/1.1.

Échafaud#

bash
bext new my-app --template @bext/starter-django
cd my-app
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
python manage.py migrate
python manage.py collectstatic --noinput

Gunicorn (synchronisation WSGI)#

Gunicorn est la valeur par défaut pour les déploiements Django classiques : vues synchronisées, requêtes ORM, réponses basées sur des modèles. Choisissez-le si vous n'écrivez pas Fonctions d'affichage async def.

bash
gunicorn myproject.wsgi \
  --bind 127.0.0.1:8000 \
  --workers 4 \
  --threads 2 \
  --timeout 30

Règle générale : workers = 2 * cores + 1 pour le travail Django lié aux IO ; bext absorbe la gigue du démarrage à froid et met en file d'attente les rafales en périphérie, vous n'avez donc généralement pas besoin d'autant de travailleurs que vous le feriez derrière nginx.

Uvicorn (ASGI asynchrone)#

Uvicorn est le bon choix lorsqu'une vue est async def, lorsque vous diffusez des réponses ou lorsque vous souhaitez utiliser les canaux Django pour websockets. Il fonctionne sur uvloop et gère proprement les événements ASGI lifespan.

bash
uvicorn myproject.asgi:application \
  --host 127.0.0.1 \
  --port 8000 \
  --workers 4

bext ne se soucie pas de celui que vous choisissez : il s'agit d'une destination de proxy inverse. La commutation est systemctl stop django-gunicorn alors systemctl start django-uvicorn ; aucun changement de configuration bext n'est nécessaire.

Fichiers statiques servis par bext#

La vue staticfiles de Django convient en développement mais ne devrait jamais s'exécuter en production. bext diffuse du contenu statique directement à partir de STATIC_ROOT avec des URL adressées par le contenu, des variantes brotli / gzip précompressées et cache-control: immutable - un ordre de grandeur de latence inférieur à celui de demander un PNG à Django.

Dans bext.config.toml :

toml
[[route_rules]]
pattern = "/static/**"
render = "static"
headers = { "cache-control" = "public, max-age=31536000, immutable" }

[[route_rules]]
pattern = "/media/**"
render = "static"

Et dans myproject/settings.py :

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

Après avoir déployé de nouveaux actifs, exécutez python manage.py collectstatic ; bext récupère les nouveaux fichiers sans rechargement car les routes statiques sont sauvegardées par le système de fichiers.

bext.config.toml#

toml
[server]
port = 3000
app_dir = "."

[framework]
type = "proxy"

[upstreams.django]
keepalive = 32
connect_timeout_ms = 2000
read_timeout_ms = 30000

[[upstreams.django.servers]]
url = "http://127.0.0.1:8000"

[upstreams.django.health]
enabled = true
path = "/"

[[route_rules]]
pattern = "/static/**"
render = "static"

[[route_rules]]
pattern = "/media/**"
render = "static"

[[route_rules]]
pattern = "/**"
proxy = "django"

[cache]
enabled = true

[waf]
enabled = true

Le démarreur est livré avec ce fichier pré-câblé. Pointez STATIC_ROOT sur ./staticfiles dans les paramètres afin que la disposition du répertoire corresponde.

unités système#

Licorne#

ini
# /etc/systemd/system/django-gunicorn.service
[Unit]
Description=Gunicorn for my Django app
After=network.target

[Service]
Type=notify
User=django
Group=django
WorkingDirectory=/srv/my-app
Environment="PATH=/srv/my-app/.venv/bin"
Environment="DJANGO_SETTINGS_MODULE=myproject.settings"
ExecStart=/srv/my-app/.venv/bin/gunicorn \
          --bind 127.0.0.1:8000 \
          --workers 4 \
          --threads 2 \
          --timeout 30 \
          myproject.wsgi
Restart=always

[Install]
WantedBy=multi-user.target

Uvicorne#

ini
# /etc/systemd/system/django-uvicorn.service
[Unit]
Description=Uvicorn for my Django app (ASGI)
After=network.target

[Service]
Type=simple
User=django
Group=django
WorkingDirectory=/srv/my-app
Environment="PATH=/srv/my-app/.venv/bin"
Environment="DJANGO_SETTINGS_MODULE=myproject.settings"
ExecStart=/srv/my-app/.venv/bin/uvicorn \
          --host 127.0.0.1 \
          --port 8000 \
          --workers 4 \
          myproject.asgi:application
Restart=always

[Install]
WantedBy=multi-user.target

Associez l’une ou l’autre unité à la propre unité systemd de bext. systemctl reload bext relit bext.config.toml sans abandonner les connexions — les déploiements Django sont indépendants des déploiements bext.

Faites confiance à l'en-tête X-Forwarded-Proto#

Conseil

Django verra chaque requête arriver via HTTP simple depuis 127.0.0.1. Sans les paramètres ci-dessous, request.is_secure() renvoie toujours False et CSRF_COOKIE_SECURE / SESSION_COOKIE_SECURE ne correspondra pas au protocole réel.

bext définit X-Forwarded-Proto et X-Forwarded-For à chaque demande proxy. Django a besoin d'un paramètre sur une seule ligne pour les honorer :

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

Avec cela en place, request.is_secure() renvoie correctement True lorsque le client est arrivé via TLS, même si la jambe amont est un simple HTTP.

Couche de mise en cache#

Associez le cache de fragments de bext avec le cache de fragments @vary_on_headers de Django / Décorateurs @cache_control. Django définit Cache-Control et bext l'honore automatiquement ; il n'y a pas d'annotation spécifique à bext.

Pour l’invalidation basée sur les balises depuis une vue Django, POST sur le point de terminaison d’administrateur bext :

python
import requests

requests.post(
    "http://127.0.0.1:3000/__bext/cache/purge",
    json={"keys": ["products"]},
)

Connexions à la base de données et vérifications de l'état#

Les vérifications de l'état en amont de bext envoient un ping à / par défaut. Pointez-les vers une vue légère (pas /health sauf si vous la définissez, pour éviter un 404) ou ajoutez un point de terminaison de santé dédié dans urls.py qui renvoie un petit corps JSON sans toucher à la base de données.

Détection de catalogue#

Les projets sont détectés automatiquement par bext site autoconfigure lorsque les trois conditions suivantes sont remplies :

  • manage.py existe à la racine du projet
  • requirements.txt ou pyproject.toml répertorie django
  • aucune autre règle-cadre ne se déclenche en premier

La règle de détection réside dans crates/bext-import/catalog/frameworks.yaml sous django.

Lacunes connues#

  • Invalidation du cache asynchrone uniquement : backends de cache asynchrone de Django sont encore en évolution ; L’invalidation du cache bext des consommateurs Channels utilise une solution de secours de pool de threads.
  • Canaux websockets : acheminer le trafic WS de style LiveView via un dédié en amont (ou un deuxième groupe en amont bext) plutôt que le même groupe qui sert le trafic requête-réponse, pour éviter de manquer d'emplacements de travail lors de connexions de longue durée.
  • Déploiements multi-sites : pour un seul fronting de processus bext plusieurs applications Django, donnez à chaque application son propre groupe en amont et ses propres règles de routage liées au nom d'hôte.

En rapport#

  • Django — documentation officielle de Django
Modifier cette page ↗Besoin d’aide ? ↗
Rechercher dans la documentation

Saisissez un sujet, une commande ou une question.