1. 概述

在使用 Docker 容器化部署 Django 应用时,数据库迁移(migration)是一个常见的操作。但有时候我们会遇到 Django 无法检测到模型变更的问题,导致无法生成迁移文件。这种情况下,很多开发者会直接选择重建容器,但这显然不是最优解。

本文将通过一个完整的示例,演示如何在 Docker Compose 环境下正确执行 Django 的数据库迁移操作。我们使用 PostgreSQL 作为数据库,并在 Linux 环境下进行演示。


2. 创建 Docker 化的 Django 项目

我们先从零开始搭建一个简单的 Django 项目,并将其容器化。

2.1 创建 Django 项目

首先,创建项目目录并进入:

$ mkdir dockerized-django-app && cd dockerized-django-app

接着创建虚拟环境并安装依赖:

$ python3 -m venv venv && source venv/bin/activate && pip install django psycopg2-binary

创建 Django 项目:

$ django-admin startproject myproject .

修改 myproject/settings.py 中的数据库配置,改为使用 PostgreSQL:

from pathlib import Path
import os

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.getenv('POSTGRES_DB', 'mydatabase'),
        'USER': os.getenv('POSTGRES_USER', 'myuser'),
        'PASSWORD': os.getenv('POSTGRES_PASSWORD', 'mypassword'),
        'HOST': 'db',
        'PORT': '5432',
    }
}

2.2 创建 Dockerfile

在项目根目录下创建 Dockerfile

FROM python:3.9

WORKDIR /app

COPY . /app

RUN pip install --no-cache-dir -r requirements.txt

EXPOSE 8000

CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]

同时创建 requirements.txt 文件:

django
psycopg2-binary

2.3 创建 docker-compose.yml

创建 docker-compose.yml 文件如下:

version: '3.9'
services:
  db:
    image: postgres
    restart: always
    environment:
      POSTGRES_DB: mydatabase
      POSTGRES_USER: myuser
      POSTGRES_PASSWORD: mypassword
    volumes:
      - postgres_data:/var/lib/postgresql/data

  web:
    build: .
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/app
    ports:
      - "8000:8000"
    depends_on:
      - db
    environment:
      DATABASE_URL: postgres://myuser:mypassword@db:5432/mydatabase

volumes:
  postgres_data:

2.4 启动服务并执行迁移

启动服务:

$ docker-compose up -d

执行数据库迁移:

$ docker-compose run web python manage.py migrate

此时 Django 会连接 PostgreSQL 并创建初始数据库结构。


3. 处理模型变更与迁移

接下来我们演示如何添加一个新模型并执行迁移。

3.1 创建新应用

myproject 目录下创建 books 应用:

$ docker-compose run web sh -c "python manage.py startapp books && ls -l && mv books myproject/"

books 添加到 INSTALLED_APPS 中:

INSTALLED_APPS = [
    ...
    'myproject.books',
]

同时确认 books/apps.py 中的 name 属性为 'myproject.books'

3.2 定义新模型

编辑 books/models.py

from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=255)
    author = models.CharField(max_length=255)
    published_date = models.DateField()

    def __str__(self):
        return self.title

3.3 执行迁移

生成迁移文件:

$ docker-compose run web python manage.py makemigrations books

应用迁移:

$ docker-compose run web python manage.py migrate

3.4 验证模型

注册模型到 admin:

from django.contrib import admin
from .models import Book

admin.site.register(Book)

创建超级用户:

$ docker-compose run web python manage.py createsuperuser

访问 http://localhost:8000/admin/,确认 Book 模型已注册。

3.5 Django 未检测到模型变更的常见问题

有时,Django 无法检测到模型变更,导致 makemigrations 无输出。以下是常见排查步骤:

检查模型是否已正确修改

确保字段确实有变化,例如添加了一个新字段:

class Book(models.Model):
    ...
    isbn = models.CharField(max_length=13, unique=True)  # 新增字段

执行 dry-run 检查

$ docker-compose run web python manage.py makemigrations --dry-run

如果没有输出,说明 Django 未检测到变化。

确认应用是否加入 INSTALLED_APPS

确保 myproject.books 已加入 INSTALLED_APPS

检查 migrations 目录是否存在

确保 books/migrations/ 存在且有迁移文件。

重启容器并清除缓存

$ docker-compose down
$ docker-compose up -d

手动删除并重新生成迁移

⚠️ 注意:此操作会删除已有迁移文件,仅用于开发环境!

$ rm -rf books/migrations/*
$ docker-compose run web python manage.py makemigrations books
$ docker-compose run web python manage.py migrate

4. 总结

本文通过一个完整的 Django + PostgreSQL + Docker Compose 示例,演示了如何在容器化环境中正确执行数据库迁移操作。我们还介绍了 Django 无法检测到模型变更的常见原因及解决方法。

通过这些实践,你可以在不频繁重建容器的前提下,实现数据库结构的同步更新,提升开发效率并保障数据一致性。

完整代码可在 GitHub 上找到。


原始标题:Performing Django Database Migrations With Docker-Compose