Django

Tutoriel 2 — Environnement “Geek” pour Django en ligne

×

Recommandés

Rapprochement bancaire : exercices corrigés et ...
Rapprochement bancaire : une méthode claire,...
En savoir plus
Présentation de Chiffres clés PPT : 3...
Une présentation de chiffres clés ressemble...
En savoir plus
Django en ligne : poser un environnement...
Chapo. Fini les “ça marche chez...
En savoir plus
📄 La fiche technique de formation :...
La mise en place d’une action...
En savoir plus
Suivi des normes sectorielles : un enjeu...
Les normes jouent un rôle important...
En savoir plus
Développer une apps mobile pour votre entreprise
Apps mobile ? Ce guide a pour objectif...
En savoir plus

Le setup qui sent le terminal, les dotfiles bien rangés et la vélocité clavier.

Pitch

Objectif simple : ouvrir un IDE cloud et obtenir un poste de dev Django qui claque — shell nerveux, prompts qui parlent, linters qui mordent, hot-reload propre, logs lisibles, raccourcis partout. Zéro bricolage manuel. Tout se déclare via conteneur + dotfiles + scripts idempotents.

Un environnement Django en ligne peut être austère ou plaisant. Version “geek”, il devient rapide, verbeux quand il faut, silencieux quand il faut, et surtout prédictible. Copiez-collez ces fichiers, poussez dans votre repo, ouvrez le workspace : votre équipe a désormais un cockpit clavier-first pour shipper sans yak-shaving.


1) Base image & devcontainer : que tout le monde voie la même machine

Dockerfile (dev)

FROM mcr.microsoft.com/devcontainers/python:3.12

# Outils CLI "geek" (rapides & lisibles)
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \
    git ripgrep fd-find fzf bat eza direnv tmux \
    && ln -s /usr/bin/fdfind /usr/local/bin/fd \
    && ln -s /usr/bin/batcat /usr/local/bin/bat \
    && rm -rf /var/lib/apt/lists/*

# Python tooling (ultra-rapide) : uv + ruff + mypy
RUN pipx install uv && pipx ensurepath
ENV PATH="/root/.local/bin:${PATH}"

# Node minimal (pour Pyright ou front léger)
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && apt-get install -y nodejs

# Starship prompt
RUN curl -fsSL https://starship.rs/install.sh | sh -s -- -y

.devcontainer/devcontainer.json

{
  "name": "django-geek-dev",
  "build": { "dockerfile": "Dockerfile" },
  "features": {},
  "settings": {
    "terminal.integrated.defaultProfile.linux": "bash",
    "editor.rulers": [100],
    "python.analysis.typeCheckingMode": "basic",
    "files.trimTrailingWhitespace": true
  },
  "postCreateCommand": "just bootstrap",
  "forwardPorts": [8000],
  "remoteEnv": {
    "DJANGO_SETTINGS_MODULE": "config.settings.dev"
  }
}

2) Dotfiles & prompt qui parle

~/.bashrc (extrait)

eval "$(direnv hook bash)"
export EDITOR="nvim"
export PIP_DISABLE_PIP_VERSION_CHECK=1
export PYTHONDONTWRITEBYTECODE=1
eval "$(starship init bash)"
alias ll='eza -lh --git --icons --group-directories-first'
alias cat='bat --paging=never'
alias g='git'

~/.config/starship.toml (prompt minimal lisible)

add_newline = false
[directory] truncation_length = 3
[python] format = "via [ $virtualenv]($style) "
[git_branch] symbol = " "
[cmd_duration] min_time = 500

~/.tmux.conf (multiplexage sobre)

setw -g mode-keys vi
set -g mouse on
bind r source-file ~/.tmux.conf \; display "reloaded"

3) Arborescence Django “opinionated”

project/
├─ .devcontainer/
├─ .env.example
├─ justfile
├─ pyproject.toml
├─ manage.py
├─ src/
│  ├─ config/
│  │  ├─ asgi.py
│  │  ├─ wsgi.py
│  │  └─ settings/{base.py,dev.py,prod.py}
│  ├─ apps/core/
│  ├─ templates/
│  └─ static/
└─ tests/

4) Dépendances & qualité : uv + ruff + pytest

pyproject.toml (extrait)

[project]
name = "django-geek"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
  "django>=5.0",
  "dj-database-url>=2.2",
  "python-dotenv>=1.0",
  "django-extensions>=3.2",
]

[project.optional-dependencies]

dev = [« pytest », « pytest-django », « ruff », « black », « mypy », « ipython »]

[tool.pytest.ini_options]

DJANGO_SETTINGS_MODULE = « config.settings.dev » pythonpath = [« src »]

Installation express

uv pip install -e ".[dev]"

5) Settings 12-Factor : sobres mais affûtés

src/config/settings/base.py

from pathlib import Path
import os, dj_database_url

BASE_DIR = Path(__file__).resolve().parents[2]
ENV = os.getenv("ENV", "dev")

def env(key, default=None):
    v = os.getenv(key, default)
    return None if v is None else v

SECRET_KEY = env("DJANGO_SECRET_KEY", "change-me")
DEBUG = env("DJANGO_DEBUG", "0") == "1"
ALLOWED_HOSTS = env("DJANGO_ALLOWED_HOSTS", "").split(",") if env("DJANGO_ALLOWED_HOSTS") else []
CSRF_TRUSTED_ORIGINS = env("DJANGO_CSRF_TRUSTED_ORIGINS","").split(",") if env("DJANGO_CSRF_TRUSTED_ORIGINS") else []

LANGUAGE_CODE = env("DJANGO_LANGUAGE_CODE", "fr-fr")
TIME_ZONE = env("DJANGO_TIME_ZONE", "Europe/Paris")
USE_I18N = True; USE_TZ = True

INSTALLED_APPS = [
    "django.contrib.admin","django.contrib.auth","django.contrib.contenttypes",
    "django.contrib.sessions","django.contrib.messages","django.contrib.staticfiles",
    "django_extensions","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"
WSGI_APPLICATION = "config.wsgi.application"
ASGI_APPLICATION = "config.asgi.application"

DATABASES = {"default": dj_database_url.parse(env("DATABASE_URL","sqlite:///db.sqlite3"))}

STATIC_URL = "/static/"; STATIC_ROOT = BASE_DIR / "staticfiles"
MEDIA_URL = "/media/";   MEDIA_ROOT = BASE_DIR / "media"

LOGGING = {
  "version": 1, "disable_existing_loggers": False,
  "handlers": {"console": {"class": "logging.StreamHandler"}},
  "root": {"handlers": ["console"], "level": env("DJANGO_LOG_LEVEL","INFO")},
}

dev.py et prod.py

# dev.py
from .base import *
DEBUG = True
INTERNAL_IPS = ["127.0.0.1"]

# prod.py
from .base import *
SECURE_SSL_REDIRECT = os.getenv("DJANGO_SSL_REDIRECT","1") == "1"
SESSION_COOKIE_SECURE = True; CSRF_COOKIE_SECURE = True
SECURE_HSTS_SECONDS = int(os.getenv("DJANGO_HSTS_SECONDS","0"))

6) Variables d’environnement : contrat d’infra

.env.example

DJANGO_SECRET_KEY=changeme
DJANGO_DEBUG=1
DJANGO_ALLOWED_HOSTS=localhost,127.0.0.1
DJANGO_CSRF_TRUSTED_ORIGINS=http://localhost:8000
DJANGO_LOG_LEVEL=INFO
DJANGO_LANGUAGE_CODE=fr-fr
DJANGO_TIME_ZONE=Europe/Paris
DATABASE_URL=sqlite:///db.sqlite3
DJANGO_SSL_REDIRECT=0
DJANGO_HSTS_SECONDS=0

direnv pour l’auto-load
.envrc

dotenv
export DJANGO_SETTINGS_MODULE=config.settings.dev

Puis :

direnv allow

7) Task runner sans friction : just au lieu de retenir 12 commandes

justfile

set shell := ["bash", "-cu"]

bootstrap:
    uv pip install -e ".[dev]"
    pre-commit install || true

run:
    python manage.py migrate
    python manage.py runserver 0.0.0.0:8000

shell:
    python manage.py shell_plus

lint:
    ruff check .
    black --check .
    mypy src

fix:
    ruff check . --fix
    black .

test:
    pytest -q

collect:
    python manage.py collectstatic --noinput

Exécution :

just bootstrap
just run

8) Expérience dev “clavier only”

Recherche ultra-rapide : rg "pattern" -n src/
Fuzzy-open un fichier : fzf puis enter
Git lisible :

git config --global core.pager "delta"
git log --graph --oneline --decorate --all

Django shell++ : just shell (via django-extensions)
Hot-reload fiable : runserver 0.0.0.0:8000 + volumes montés (devcontainer)
Multiplexage : tmux new -s dj && tmux split-window -h && tmux split-window -v
Panneau gauche : serveur. Haut droit : tests. Bas droit : logs.


9) Observabilité locale propre

Astuce logging de dev : niveaux lisibles, timestamps courts.

# dans base.py, remplacez "handlers" par:
"handlers": {
  "console": {
    "class": "logging.StreamHandler",
    "formatter": "simple"
}},
"formatters": {
  "simple": { "format": "[%(levelname).1s %(asctime)s] %(name)s: %(message)s",
              "datefmt": "%H:%M:%S" }
}

Résultat : [I 14:22:10] django.server: "GET /admin/..." 200


10) DB & services “à la carte” en dev

docker-compose.yml (optionnel)

services:
  db:
    image: postgres:16
    environment:
      POSTGRES_USER: django
      POSTGRES_PASSWORD: django
      POSTGRES_DB: django
    ports: ["5432:5432"]
  redis:
    image: redis:7
    ports: ["6379:6379"]

Env : DATABASE_URL=postgres://django:django@localhost:5432/django
Bonus Celery/Beat en split-process via Procfile si besoin.


11) Qualité automatique

pre-commit (extrait .pre-commit-config.yaml)

repos:
- repo: https://github.com/psf/black
  rev: 24.8.0
  hooks: [{id: black}]
- repo: https://github.com/astral-sh/ruff-pre-commit
  rev: v0.6.9
  hooks: [{id: ruff}]
- repo: https://github.com/pre-commit/pre-commit-hooks
  rev: v4.6.0
  hooks:
    - id: end-of-file-fixer
    - id: detect-private-key

Une fois installé : chaque commit est “peigné” automatiquement.


12) Routine quotidienne (ultra-courte)

Ouvrir le workspace → just run → coder → just test → commit/push.
Aucun copier-coller de commandes ésotériques, aucune divergence locale. L’IDE cloud, le conteneur et les dotfiles font le gros du travail.


13) Débogage “geek”

python manage.py runserver_plus (Werkzeug debugger — via django-extensions).
ipdb/breakpoint() pour pause granulaire.
pytest -k nom -q exécute un seul test, plus vite que tout.
• Profilage express :

from django_extensions.management.commands.runserver_plus import Command
# ou utilisez --print-sql / django-silk en local

De l’IDE cloud à la préprod/prod (Geek edition)

But. Transformer votre setup Django “en ligne” en un pipeline CI/CD prêt pour la préprod et la prod : build Docker multi-stage, statiques via WhiteNoise/CDN, médias sur stockage objet, migrations automatiques, workers Celery, healthchecks et monitoring.

1) Architecture d’exécution (vue rapide)

  • web : gunicorn config.wsgi:application
  • worker : celery -A config worker -l info
  • scheduler : celery -A config beat -l info
  • services : Postgres, Redis, stockage objet (S3-compatible)
  • statiques : WhiteNoise (et/ou CDN)
  • médias : bucket S3, jamais sur le conteneur
  • logs : stdout/stderr (niveau piloté par env)

2) Dockerfile prod (multi-stage, slim & rapide)

# syntax=docker/dockerfile:1
FROM python:3.12-slim AS build
WORKDIR /app
RUN apt-get update && apt-get install -y build-essential libpq-dev && rm -rf /var/lib/apt/lists/*
COPY pyproject.toml ./
RUN pip install --upgrade pip && pip install --no-cache-dir "pip-tools"
# Si vous utilisez requirements.txt: COPY requirements.txt . && pip install -r requirements.txt

FROM python:3.12-slim AS runtime
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1
WORKDIR /app
RUN useradd -m django && apt-get update && apt-get install -y libpq5 && rm -rf /var/lib/apt/lists/*
COPY --from=build /usr/local /usr/local
COPY ./src ./src
COPY manage.py gunicorn.conf.py ./
ENV DJANGO_SETTINGS_MODULE=config.settings.prod
USER django
CMD ["gunicorn","-c","gunicorn.conf.py","config.wsgi:application"]

gunicorn.conf.py (prod)

bind = "0.0.0.0:8000"
workers = 3
threads = 2
timeout = 60
graceful_timeout = 30
accesslog = "-"   # stdout
errorlog  = "-"   # stderr

3) Statiques et WhiteNoise

settings/prod.py (extraits)

from .base import *
INSTALLED_APPS = ["whitenoise.runserver_nostatic", *INSTALLED_APPS]
MIDDLEWARE.insert(1, "whitenoise.middleware.WhiteNoiseMiddleware")
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
SECURE_SSL_REDIRECT = os.getenv("DJANGO_SSL_REDIRECT","1") == "1"
SESSION_COOKIE_SECURE = True; CSRF_COOKIE_SECURE = True
SECURE_HSTS_SECONDS = int(os.getenv("DJANGO_HSTS_SECONDS","31536000"))

Build/collectstatic (CI avant image finale)

python manage.py collectstatic --noinput

4) Médias sur S3 (django-storages)

# settings/prod.py (suite)
INSTALLED_APPS += ["storages"]
DEFAULT_FILE_STORAGE = "storages.backends.s3boto3.S3Boto3Storage"
AWS_ACCESS_KEY_ID = os.getenv("AWS_ACCESS_KEY_ID")
AWS_SECRET_ACCESS_KEY = os.getenv("AWS_SECRET_ACCESS_KEY")
AWS_STORAGE_BUCKET_NAME = os.getenv("AWS_STORAGE_BUCKET_NAME")
AWS_S3_REGION_NAME = os.getenv("AWS_S3_REGION_NAME", "eu-west-1")
AWS_S3_OBJECT_PARAMETERS = {"CacheControl": "max-age=31536000, public"}

Env requis

AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_STORAGE_BUCKET_NAME, AWS_S3_REGION_NAME

5) Healthchecks & readiness

Une vue “prête” pour l’orchestrateur :

# src/apps/core/views.py
from django.http import JsonResponse
def health(request): return JsonResponse({"status":"ok"})
def ready(request):  return JsonResponse({"db":"ok","cache":"ok"})

# src/config/urls.py
from django.urls import path
from apps.core.views import health, ready
urlpatterns = [path("health/", health), path("ready/", ready)]

6) Celery & Redis

src/config/celery.py

import os
from celery import Celery
os.environ.setdefault("DJANGO_SETTINGS_MODULE","config.settings.prod")
app = Celery("config")
app.config_from_object("django.conf:settings", namespace="CELERY")
app.autodiscover_tasks()

Env (ex.)

CELERY_BROKER_URL=redis://redis:6379/0
CELERY_RESULT_BACKEND=redis://redis:6379/1

7) GitHub Actions — pipeline CI/CD minimal

.github/workflows/ci.yml

name: ci
on:
  push: { branches: [main] }
  pull_request: {}
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with: { python-version: '3.12' }
      - name: Install deps
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt
      - name: Lint & Tests
        run: |
          ruff check .
          black --check .
          pytest -q

.github/workflows/cd.yml (build & push image + déploiement via SSH)

name: cd
on:
  push: { branches: [main] }
jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    permissions: { contents: read, packages: write }
    steps:
      - uses: actions/checkout@v4
      - name: Login GHCR
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - name: Build & Push
        uses: docker/build-push-action@v6
        with:
          push: true
          tags: ghcr.io/${{ github.repository }}:latest
      - name: Deploy (SSH)
        uses: appleboy/ssh-action@v1.0.3
        with:
          host: ${{ secrets.SSH_HOST }}
          username: ${{ secrets.SSH_USER }}
          key: ${{ secrets.SSH_KEY }}
          script: |
            docker pull ghcr.io/${{ github.repository }}:latest
            docker compose -f /srv/app/compose.prod.yml up -d --force-recreate
            docker compose -f /srv/app/compose.prod.yml exec -T web python manage.py migrate

8) compose.prod.yml (web + worker + beat)

services:
  web:
    image: ghcr.io/owner/repo:latest
    env_file: /srv/app/.env
    ports: ["80:8000"]
    depends_on: [db, redis]
    restart: always
  worker:
    image: ghcr.io/owner/repo:latest
    command: celery -A config worker -l info
    env_file: /srv/app/.env
    depends_on: [redis]
    restart: always
  beat:
    image: ghcr.io/owner/repo:latest
    command: celery -A config beat -l info
    env_file: /srv/app/.env
    depends_on: [redis]
    restart: always
  db:
    image: postgres:16
    volumes: ["pgdata:/var/lib/postgresql/data"]
    environment:
      POSTGRES_DB: django
      POSTGRES_USER: django
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
  redis:
    image: redis:7
volumes:
  pgdata:

9) Secrets & variables (checklist)

  • Django : DJANGO_SECRET_KEY, DJANGO_ALLOWED_HOSTS, DJANGO_CSRF_TRUSTED_ORIGINS, DJANGO_LOG_LEVEL
  • DB/Cache : DATABASE_URL, CELERY_BROKER_URL, CELERY_RESULT_BACKEND
  • Sécurité : DJANGO_SSL_REDIRECT=1, DJANGO_HSTS_SECONDS=31536000
  • I18N/TZ : DJANGO_LANGUAGE_CODE, DJANGO_TIME_ZONE
  • Stockage : clés S3 si médias externes

10) Monitoring minimal (Sentry)

# settings/prod.py
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration
SENTRY_DSN = os.getenv("SENTRY_DSN")
if SENTRY_DSN:
    sentry_sdk.init(dsn=SENTRY_DSN, integrations=[DjangoIntegration()], traces_sample_rate=0.2)

11) Runbook de déploiement (récap)

  1. CI : lint + tests → OK
  2. Build image → push registry
  3. CD : pull sur serveur, compose up -d
  4. Migrations : manage.py migrate (étape dédiée)
  5. Health : /health/ et /ready/ → 200
  6. Roll-back : repasser au tag précédent, relancer compose

12) Panneaux rouges (troubleshooting)

  • 403 CSRF : URL prod manquante dans CSRF_TRUSTED_ORIGINS
  • DisallowedHost : host non listé dans ALLOWED_HOSTS
  • Statiques 404 : collectstatic oublié ou mauvais STATICFILES_STORAGE
  • Uploads perdus : pas de bucket S3 → activer DEFAULT_FILE_STORAGE
  • Celery muet : CELERY_BROKER_URL incorrect / Redis non joignable
  • Timeout : ajuster workers/threads/timeout de Gunicorn ou index DB

Recommandés

Django en ligne : poser un environnement...
Chapo. Fini les “ça marche chez...
En savoir plus
Candidature spontanée par courrier : 10 lettres...
Aujourd’hui, où le clic remplace souvent...
En savoir plus
La Planification de Scénarios : Définition et...
Toute organisation performante s’appuie sur une...
En savoir plus
Analyse SWOT pour un Restaurant : Exemple
La Matrice SWOT, une méthode d'analyse...
En savoir plus
Modèle de Tableau de Bord Magasin de...
Cet article explore un modèle de...
En savoir plus
Guide complet de l'Automatisation de la Chaîne...
Dans cet article, nous allons explorer...
En savoir plus
AZ

Share
Published by
AZ

Recent Posts

Classification des Documents : Organiser et Automatiser la Gestion Documentaire

Dans toute organisation moderne — entreprise, association, service administratif ou bureau de projet — la…

2 jours ago

Modèle de Bilan Actif Passif sur Excel : Concevoir un tableau comptable clair et automatisé

Dans la pratique comptable, le bilan constitue l’un des documents les plus fondamentaux pour comprendre…

2 jours ago

Fiche Méthode analyse linéaire + guide complet pour la réussir

L’analyse linéaire impressionne souvent plus qu’elle ne le devrait. Au moment d’aborder l’oral du bac…

3 jours ago

Analyse linéaire au bac français : méthode complète, exemples et conseils pour réussir l’oral

L’analyse linéaire occupe une place centrale à l’oral du bac français. C’est l’exercice qui permet…

3 jours ago

Créer une fiche de suivi en ligne : générateur personnalisable à imprimer

Créer une fiche de suivi claire et adaptée à son activité prend souvent plus de…

3 jours ago

Préparation physique football avec ballon : Fiche Word utile

Comment améliorer sa condition physique tout en travaillant la technique Quand on parle de préparation…

3 jours ago

This website uses cookies.