You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker化Django:迁移中执行自定义SQL脚本遇报错的解决方法

解决Django迁移中执行自定义SQL脚本的问题

我来帮你梳理清楚问题根源,以及如何正确实现让自定义SQL脚本在初始迁移完成后执行:

问题核心原因

你当前的代码有两个关键问题,直接导致了报错:

  1. RunPython的调用方式错误:你在migrations.RunPython()里直接执行了load_data_from_sql('my_app_base.sql'),这会让Django在生成迁移文件(makemigrations阶段)就触发SQL脚本执行,而不是等到实际迁移(migrate阶段)才运行。此时数据库里连auth_user表都还没创建,自然会抛出relation does not exist的错误。
  2. 迁移依赖的完整性不足:你的数据迁移只依赖了自身应用的初始迁移,但没有明确依赖Django auth模块的初始迁移,无法保证auth_user表先于你的SQL脚本创建完成。

正确实现步骤

1. 修复迁移文件的RunPython调用

修改my_app/migrations/0001_initial_data.py,调整函数传递方式,确保SQL脚本只在migrate阶段执行:

import os
from functools import partial
from django.db import migrations, connection

def load_data_from_sql(apps, schema_editor, filename):
    # 必须保留apps和schema_editor参数,这是RunPython要求的回调签名
    file_path = os.path.join(os.path.dirname(__file__), '../sql/', filename)
    with open(file_path, 'r') as f:
        sql_statement = f.read()
    with connection.cursor() as cursor:
        cursor.execute(sql_statement)

class Migration(migrations.Migration):
    dependencies = [
        ('my_app', '0001_initial'),
        # 明确依赖auth模块的初始迁移,确保auth_user表已创建
        ('auth', '0001_initial'),
    ]
    operations = [
        # 使用partial传递参数,避免提前执行函数
        migrations.RunPython(partial(load_data_from_sql, filename='my_app_base.sql'))
    ]

如果不想用functools.partial,也可以用lambda包装:

operations = [
    migrations.RunPython(lambda apps, schema_editor: load_data_from_sql(apps, schema_editor, 'my_app_base.sql'))
]

2. 优化entrypoint.sh的命令逻辑

你的entrypoint.sh里的makemigrations不需要每次容器启动都执行(迁移文件应该提前生成并提交到代码库),建议调整为仅在开发环境可选执行,避免不必要的数据库交互:

#!/bin/sh
if [ "$DATABASE" = "postgres" ]
then
    echo "Waiting for postgres..."
    while ! nc -z $SQL_HOST $SQL_PORT; do
        sleep 0.1
    done
    echo "PostgreSQL started"
fi

# 仅在开发环境自动生成迁移(可选,根据你的需求调整)
# if [ "$DEBUG" = "True" ]; then
#     python manage.py makemigrations my_app
# fi

python manage.py migrate
exec "$@"

3. 正确的执行流程

现在按以下步骤操作即可正常运行:

  • 先清理之前可能生成的错误迁移文件,然后重新生成正确的迁移:
    docker-compose exec web python manage.py makemigrations my_app
    
  • 重新构建并启动容器,entrypoint.sh会自动执行迁移流程:
    docker-compose up --build
    

为什么之前的临时操作能成功?

你提到删除0001_initial_data.py后能正常建表,之后再添加就能成功,是因为此时数据库已经完成了auth_user和my_app表的创建,再执行迁移时,SQL脚本是在migrate阶段调用的,数据库状态已经符合要求,所以不会报错。

内容的提问来源于stack exchange,提问作者zar3bski

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:33:09