> ## Documentation Index
> Fetch the complete documentation index at: https://docs.devin.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Dockeriser une application Django avec Postgres et Redis

export const UseCaseHero = ({title, description, prompt, category, features, devinUrl, agent, intent, playbookId, type}) => {
  const encodedPrompt = encodeURIComponent(prompt || '');
  const tag = 'docs-use-case-gallery';
  const utm = 'utm_source=docs&utm_medium=use-case-gallery&utm_campaign=hero-cta';
  const agentParams = (agent ? '&agent=' + agent : '') + (intent ? '&intent=' + intent : '') + (playbookId ? '&playbookId=' + playbookId : '');
  const devinHref = type === 'schedule' ? 'https://app.devin.ai/settings/schedules/create?' + utm + agentParams + (prompt ? '&prompt=' + encodedPrompt : '') : type === 'review' ? 'https://app.devin.ai/review?' + utm : agent === 'ada' ? 'https://app.devin.ai/search?' + utm + '&noSubmit=true' + (prompt ? '&prompt=' + encodedPrompt : '') : devinUrl ? devinUrl.includes('?') ? devinUrl + '&' + utm + agentParams : devinUrl + '?' + utm + agentParams : prompt ? 'https://app.devin.ai/?tags=' + tag + '&' + utm + agentParams + '&prompt=' + encodedPrompt : 'https://app.devin.ai/?' + utm + agentParams;
  const buttonLabel = type === 'schedule' ? 'Schedule in Devin ↗' : type === 'review' ? 'Set Up Devin Review ↗' : agent === 'advanced' ? 'Try in Devin ↗' : agent === 'dana' ? 'Try in Dana ↗' : agent === 'ada' ? 'Try in Ask Devin ↗' : 'Try in Devin ↗';
  const featureList = features ? features.split(',').map(f => f.trim()) : [];
  return <div className="uc-hero">
      <div className="uc-hero-inner">
        <div className="uc-hero-left">
          <h1 className="uc-hero-title">{title}</h1>
          <p className="uc-hero-desc">{description}</p>
          <div>
            <a href={devinHref} target="_blank" rel="noopener noreferrer" className="try-in-devin-btn">
              {buttonLabel}
            </a>
          </div>
        </div>
        <div className="uc-hero-meta">
          <div className="uc-meta-item">
            <span className="uc-meta-label">Author</span>
            <span className="uc-meta-value">Cognition</span>
          </div>
          <div className="uc-meta-item">
            <span className="uc-meta-label">Category</span>
            <span className="uc-meta-value">{category}</span>
          </div>
          {featureList.length > 0 && <div className="uc-meta-item">
              <span className="uc-meta-label">Features</span>
              <span className="uc-meta-value">{featureList.join(', ')}</span>
            </div>}
        </div>
      </div>
    </div>;
};

export const PromptBlock = ({children, type, agent, intent, playbookId}) => {
  var utm = 'utm_source=docs&utm_medium=use-case-gallery&utm_campaign=prompt-block';
  var tag = 'docs-use-case-gallery';
  var agentParams = (agent ? '&agent=' + agent : '') + (intent ? '&intent=' + intent : '') + (playbookId ? '&playbookId=' + playbookId : '');
  var label = type === 'schedule' ? 'Schedule in Devin' : type === 'playbook' ? 'Create Playbook' : type === 'knowledge' ? 'Add to Knowledge' : agent === 'advanced' ? 'Try in Devin' : agent === 'dana' ? 'Try in Dana' : agent === 'ada' ? 'Try in Ask Devin' : 'Try in Devin';
  var buildUrl = function (text) {
    var encoded = encodeURIComponent(text);
    if (type === 'schedule') return 'https://app.devin.ai/settings/schedules/create?' + utm + agentParams + '&prompt=' + encoded;
    if (type === 'playbook') return 'https://app.devin.ai/settings/playbooks/create?' + utm + '&body=' + encoded;
    if (type === 'knowledge') return 'https://app.devin.ai/knowledge?' + utm + '&body=' + encoded;
    if (agent === 'ada') return 'https://app.devin.ai/search?' + utm + '&noSubmit=true&prompt=' + encoded;
    return 'https://app.devin.ai/?tags=' + tag + '&' + utm + agentParams + '&prompt=' + encoded;
  };
  const ref = React.useRef(null);
  const [href, setHref] = React.useState('#');
  React.useEffect(() => {
    if (!ref.current) return;
    var codeEl = ref.current.querySelector('pre code');
    if (codeEl) {
      var text = codeEl.textContent.trim();
      if (text) setHref(buildUrl(text));
    }
    var header = ref.current.querySelector('[data-component-part="code-block-header"]');
    if (header && !header.querySelector('.prompt-block-devin-link')) {
      var link = document.createElement('a');
      link.href = href;
      link.target = '_blank';
      link.rel = 'noopener noreferrer';
      link.className = 'prompt-block-devin-link';
      link.style.cssText = 'display:inline-flex;align-items:center;gap:6px;text-decoration:none;color:#fff;font-size:11px;font-weight:500;padding:4px 10px;border-radius:6px;white-space:nowrap;background:#317CFF;transition:background 0.2s;margin-left:8px;';
      link.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg> ' + label;
      link.onmouseenter = function () {
        link.style.background = '#2968D9';
      };
      link.onmouseleave = function () {
        link.style.background = '#317CFF';
      };
      header.appendChild(link);
    }
    var existingLink = ref.current.querySelector('.prompt-block-devin-link');
    if (existingLink && href !== '#') existingLink.href = href;
  });
  return <div className="prompt-block" ref={ref}>{children}</div>;
};

<UseCaseHero title="Dockeriser une application Django avec Postgres et Redis" description="Devin écrit un Dockerfile multi-étapes, un docker-compose.yml avec Django, PostgreSQL et Redis, puis construit et exécute la stack pour vérifier qu'elle fonctionne." prompt="Dockerise l'API Django dans src/. Elle utilise PostgreSQL pour la base de données et Redis pour la mise en cache et les files de tâches Celery. Dockerfile multi-étapes avec python:3.12-slim, docker-compose.yml avec Django (gunicorn), PostgreSQL 16, Redis 7 et un worker Celery. Exécute le tout sous un utilisateur non-root, avec un health check sur /api/health/. Construis l'image, exécute docker-compose up, vérifie que l'API répond, lance la suite de tests à l'intérieur du conteneur. Si quelque chose échoue, débogue et corrige — continue d'itérer jusqu'à ce que tout fonctionne. N'ouvre pas de PR avant que l'ensemble de la stack ne démarre proprement et que tous les tests réussissent." category="Développement de fonctionnalités" features="" />

<div className="uc-detail-wrapper">
  <Tip>Vous ne souhaitez pas effectuer cette configuration manuellement ? Collez un lien vers cette page dans une session Devin et demandez-lui de tout configurer pour vous.</Tip>

  <Steps>
    <Step title="(Facultatif) Délimiter le périmètre du projet avec Ask Devin">
      Si vous ne savez pas sur quels services repose votre application Django ni comment le projet est structuré, utilisez [Ask Devin](https://app.devin.ai/search?utm_source=docs\&utm_medium=use-case-gallery) pour commencer votre analyse :

      <PromptBlock agent="ada">
        ```txt Délimiter le périmètre du projet Django pour la conteneurisation theme={null}
        De quoi notre application Django dans src/ dépend-elle ?
        1. À quelles bases de données et à quels caches se connecte-t-elle ?
        2. Utilise-t-elle Celery ou des workers en arrière-plan ?
        3. Que contiennent requirements.txt ou pyproject.toml ?
        4. Existe-t-il déjà des fichiers Docker ou des configurations de déploiement ?
        5. Comment l'application gère-t-elle les fichiers statiques et les médias ?
        ```
      </PromptBlock>

      Vous pouvez également démarrer une session Devin directement depuis Ask Devin, et Devin conservera tout ce qu'il a appris comme contexte.
    </Step>

    <Step title="Transmettez à Devin votre projet Django et votre fichier requirements.txt">
      Indiquez à Devin quel projet Django containeriser et mentionnez tout besoin spécifique : préférences d’image de base, services dont l’application dépend ou contraintes de taille d’image. Devin lit votre `requirements.txt` ou `pyproject.toml` pour déduire le reste.

      <PromptBlock>
        ```txt Dockeriser une API Django avec Postgres et Redis theme={null}
        Conteneurise l’API Django située dans src/. Elle utilise PostgreSQL pour la base
        de données et Redis pour la mise en cache et les files de tâches Celery.

        - Dockerfile multi‑étapes : installer les dépendances dans une étape de build (builder),
          copier uniquement le venv dans une image d’exécution python:3.12-slim minimale
        - docker-compose.yml avec Django (gunicorn), PostgreSQL 16 et Redis 7
        - .dockerignore qui exclut les tests, la documentation, .git et __pycache__
        - Exécuter sous un utilisateur non‑root
        - Health check sur /api/health/
        - Worker Celery comme service séparé dans compose

        ## Tests et vérification
        - Construire l’image et exécuter docker-compose up
        - Attendre que tous les services soient opérationnels
        - Vérifier que l’API répond sur localhost:8000/api/health/
        - Exécuter la suite de tests Django à l’intérieur du conteneur
        - Si quelque chose échoue — erreurs de build, variables d’environnement manquantes,
          problèmes de connexion, tests en échec — déboguer et corriger. Continuer
          à itérer jusqu’à ce que toute la stack démarre proprement et que tous les tests passent.
        - Ne pas ouvrir de PR tant que tout ne fonctionne pas de bout en bout
        ```
      </PromptBlock>
    </Step>

    <Step title="Devin analyse et construit">
      Devin lit votre projet Django et les fichiers de dépendance pour comprendre le processus de build, puis génère la configuration Docker :

      1. **Lit les fichiers de dépendance** — Analyse `requirements.txt` ou `pyproject.toml`, identifie Django, psycopg2, redis, celery et gunicorn
      2. **Écrit le Dockerfile** — Crée un build multi-étapes qui installe les dépendances dans une étape de build et copie l'environnement virtuel dans une image d'exécution minimale `python:3.12-slim`

      ```dockerfile theme={null}
      # ---- Builder ----
      FROM python:3.12-slim AS builder
      WORKDIR /app
      COPY requirements.txt .
      RUN python -m venv /opt/venv \
          && /opt/venv/bin/pip install --no-cache-dir -r requirements.txt

      # ---- Runtime ----
      FROM python:3.12-slim
      RUN groupadd -r django && useradd -r -g django django
      COPY --from=builder /opt/venv /opt/venv
      ENV PATH="/opt/venv/bin:$PATH"
      WORKDIR /app
      COPY src/ .
      RUN python manage.py collectstatic --noinput
      EXPOSE 8000
      USER django
      CMD ["gunicorn", "config.wsgi:application", "--bind", "0.0.0.0:8000", "--workers", "3"]
      ```

      3. **Crée le fichier docker-compose.yml** — Ajoute Django, PostgreSQL, Redis et un worker Celery, avec des contrôles d’état, des volumes et un réseau partagé

      ```yaml theme={null}
      services:
        web:
          build: .
          ports:
            - "8000:8000"
          env_file: .env
          depends_on:
            db:
              condition: service_healthy
            redis:
              condition: service_healthy
          healthcheck:
            test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/api/health/')"]
            interval: 10s
            retries: 3

        db:
          image: postgres:16-alpine
          environment:
            POSTGRES_DB: app_db
            POSTGRES_USER: app_user
            POSTGRES_PASSWORD: app_pass
          volumes:
            - pgdata:/var/lib/postgresql/data
          healthcheck:
            test: ["CMD-SHELL", "pg_isready -U app_user -d app_db"]
            interval: 5s
            retries: 5

        redis:
          image: redis:7-alpine
          healthcheck:
            test: ["CMD", "redis-cli", "ping"]
            interval: 5s
            retries: 5

        celery:
          build: .
          command: celery -A config worker -l info
          env_file: .env
          depends_on:
            db:
              condition: service_healthy
            redis:
              condition: service_healthy

      volumes:
        pgdata:
      ```

      4. **Ajoute .dockerignore** — Exclut les fichiers qui n’appartiennent pas au contexte de build (`__pycache__`, `.git`, `tests/`, `docs/`, `*.pyc`)
      5. **Exécute `docker compose up --build`** — Construit l’image et démarre tous les services dans le terminal de Devin
      6. **Vérifie l’application** — Envoie une requête `curl` vers `/api/health/` pour confirmer que Django démarre correctement, se connecte à PostgreSQL et accède à Redis
    </Step>

    <Step title="Pilotez la session avec des commandes slash">
      Utilisez les commandes slash pendant la session pour orienter le flux de travail de Devin :

      * **`/plan`** — Demandez à Devin de présenter sa démarche avant d’écrire toute configuration Docker. Passez en revue le plan et proposez des modifications.
      * **`/test`** — Demandez à Devin de reconstruire et de revérifier la pile de conteneurs. Utilisez cette commande après chaque modification pour détecter les problèmes le plus tôt possible.
      * **`/review`** — Demandez à Devin de relire son propre Dockerfile et la configuration Compose afin de détecter les problèmes de sécurité, d’optimiser la taille de l’image et d’appliquer les bonnes pratiques avant d’ouvrir la PR.
    </Step>

    <Step title="Valider et itérer">
      Une fois que Devin a ouvert la PR, passez en revue les fichiers générés. Suites possibles :

      <PromptBlock>
        ```txt Optimiser la taille de l'image theme={null}
        L'image Docker fait 520 Mo. Réduisez sa taille : assurez-vous que nous ne copions
        pas de fichiers inutiles, supprimez les fichiers .pyc du venv et retirez pip
        de l'image finale.
        ```
      </PromptBlock>

      <PromptBlock>
        ```txt Ajouter le rechargement à chaud en dev theme={null}
        Ajoutez un fichier docker-compose.override.yml pour le développement local qui monte
        le répertoire source et exécute le serveur de développement de Django avec rechargement
        automatique au lieu de gunicorn.
        ```
      </PromptBlock>

      <PromptBlock>
        ```txt Ajouter un build Docker en CI theme={null}
        Créez un workflow GitHub Actions qui construit l'image Docker à
        chaque PR, exécute pytest dans le conteneur et la publie sur ECR lors
        de la fusion sur main. Marquez-la avec le SHA Git.
        ```
      </PromptBlock>
    </Step>

    <Step title="Examinez la PR avec Devin Review">
      Une fois que Devin a ouvert la PR, utilisez [Devin Review](https://app.devin.ai/review?utm_source=docs\&utm_medium=use-case-gallery) pour examiner la configuration Docker. Devin Review peut détecter des problèmes de sécurité (exécution en tant que root, secrets exposés), le non-respect de certaines bonnes pratiques (pas de `.dockerignore`, aucun health check défini) ainsi que des incohérences avec votre infrastructure existante.
    </Step>
  </Steps>
</div>
