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

开启sql_safe_update的MariaDB中Django回滚迁移报错求助

问题

在MariaDB开启sql_safe_update模式的情况下,回滚Django迁移时遇到报错。执行的回滚SQL语句为:

ALTER TABLE `user` DROP COLUMN `pin_code`;

收到Django返回的错误:

MySQLdb.OperationalError: (1175, 'You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column')

由于MySQL DDL语句不支持事务,列已被删除但迁移回滚失败,数据库处于不一致状态,使用--fake参数仍报相同错误。

请问:

  1. 能否让Django仅在迁移期间临时关闭sql_safe_update?(无法全局关闭,数据库管理员不同意)
  2. 为何删除列需要WHERE语句?
解答

一、临时在迁移期间关闭sql_safe_update

完全可以通过自定义Django迁移操作实现,不用全局修改数据库配置:

  • 要么新建一个空迁移文件,要么修改现有迁移的回滚逻辑,在操作里先执行SET sql_safe_updates=0;关闭安全模式,执行完删列的DDL后再恢复sql_safe_updates=1;。
  • 用Django的RunSQL操作就能实现,示例代码如下:
from django.db import migrations, models

class Migration(migrations.Migration):
    dependencies = [
        ('你的应用名', '上一个迁移文件的名称'),
    ]

    operations = [
        # 临时关闭安全更新模式
        migrations.RunSQL(
            "SET sql_safe_updates=0;",
            reverse_sql="SET sql_safe_updates=0;",
        ),
        # 执行删列操作,回滚时添加列(注意字段类型要和原字段一致)
        migrations.RunSQL(
            "ALTER TABLE `user` DROP COLUMN `pin_code`;",
            reverse_sql="ALTER TABLE `user` ADD COLUMN `pin_code` VARCHAR(6);", # 这里根据实际字段类型调整
        ),
        # 恢复安全更新模式
        migrations.RunSQL(
            "SET sql_safe_updates=1;",
            reverse_sql="SET sql_safe_updates=1;",
        ),
    ]
  • 针对你现在已经失败的情况:先手动确认列的状态(已经被删除的话),然后用python manage.py migrate --fake 应用名 迁移文件名标记该迁移为已完成,避免重复执行错误操作。

二、为什么删除列会触发safe update检查

这其实是MariaDB/MySQL的一个设计缺陷或者小bug:sql_safe_update本来是用来限制UPDATE/DELETE这类没有WHERE条件、或者WHERE没用到索引的DML语句,但部分版本里会错误地把ALTER TABLE DROP COLUMN这类DDL也纳入检查范围。本质上删列根本不需要WHERE,纯粹是数据库的误判导致了这个错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 13:32:49