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

Django模型删除字段或表时保留已有数据及新增unique字段问题咨询

Django 生产环境模型变更数据兼容方案

场景1:删除已上线存有待保留数据的字段column1

生产环境删除字段前必须先完成数据归档,禁止直接删除字段导致数据丢失,操作步骤如下:

  • 前置操作:全量备份现有生产数据库,确认备份可正常恢复
  • 步骤1:新增归档模型存储待删除字段的历史数据,示例模型定义如下:
from django.db import models
from your_app.models import YourOriginalModel

class ArchivedColumn1Data(models.Model):
    original_id = models.IntegerField(verbose_name="原记录ID", db_index=True)
    column1 = models.CharField(verbose_name="归档的column1值", max_length=255) # 字段类型和原column1保持一致
    archive_time = models.DateTimeField(verbose_name="归档时间", auto_now_add=True)

    class Meta:
        db_table = "archived_column1_data"
  • 步骤2:执行python manage.py makemigrations --empty your_app_name生成空迁移文件,在迁移文件中添加数据归档逻辑,示例代码如下:
from django.db import migrations

def archive_column1(apps, schema_editor):
    YourOriginalModel = apps.get_model('your_app_name', 'YourOriginalModel')
    ArchivedColumn1Data = apps.get_model('your_app_name', 'ArchivedColumn1Data')
    # 批量归档数据,数据量大时分页处理避免OOM
    batch_size = 1000
    offset = 0
    while True:
        records = YourOriginalModel.objects.all()[offset:offset+batch_size]
        if not records:
            break
        archive_objs = [
            ArchivedColumn1Data(original_id=record.id, column1=record.column1)
            for record in records
        ]
        ArchivedColumn1Data.objects.bulk_create(archive_objs)
        offset += batch_size

class Migration(migrations.Migration):
    dependencies = [
        ('your_app_name', '000x_prev_migration_id'), # 替换为上一个迁移文件的编号
    ]

    operations = [
        migrations.RunPython(archive_column1),
    ]
  • 步骤3:执行python manage.py migrate完成数据归档,校验归档表数据和原表数据一致性
  • 步骤4:删除原模型中的column1字段,生成新的迁移文件执行即可,后续需要历史数据时直接查询归档表

如果暂时不确定是否完全不需要该字段,也可以仅将原字段的editable属性设为False,并在admin、业务接口中隐藏该字段,不执行删除操作,数据会直接保留在原表中。

场景2:存量数据存在时新增带unique约束、不允许为null的字段column2

直接添加非空唯一字段会触发迁移报错,需要分三步完成变更:

  • 前置操作:全量备份现有生产数据库,确认备份可正常恢复
  • 步骤1:先给column2设置null=True,暂不添加unique和非空约束,示例模型定义:
class YourOriginalModel(models.Model):
    # 原有其他字段
    column2 = models.CharField(verbose_name="新字段", max_length=64, null=True)

生成迁移文件后执行,此时存量数据的column2值均为null

  • 步骤2:根据业务规则为所有存量数据生成唯一非空的column2值,可通过自定义迁移实现批量填充,示例逻辑如下:
from django.db import migrations

def fill_column2(apps, schema_editor):
    YourOriginalModel = apps.get_model('your_app_name', 'YourOriginalModel')
    batch_size = 1000
    offset = 0
    while True:
        records = YourOriginalModel.objects.filter(column2__isnull=True)[offset:offset+batch_size]
        if not records:
            break
        for record in records:
            # 替换为业务侧的唯一值生成规则,示例为前缀+主键ID
            record.column2 = f"BIZ_RULE_PREFIX_{record.id}"
        YourOriginalModel.objects.bulk_update(records, ['column2'])
        offset += batch_size

class Migration(migrations.Migration):
    dependencies = [
        ('your_app_name', '000x_add_nullable_column2'), # 替换为上一步添加column2的迁移编号
    ]

    operations = [
        migrations.RunPython(fill_column2),
    ]

执行迁移后校验所有存量数据的column2值均非空且无重复

  • 步骤3:修改column2的模型定义,去掉null=True,添加unique=True:
class YourOriginalModel(models.Model):
    # 原有其他字段
    column2 = models.CharField(verbose_name="新字段", max_length=64, unique=True)

生成迁移文件后执行即可。后续新增记录可通过重写save方法、pre_save信号或者业务层逻辑自动生成符合规则的唯一值,避免插入报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 18:06:04