Django-simple-history无法生成历史数据且迁移报多主键错误
问题根源分析
- 双主键冲突:原模型使用UUID作为主键,django-simple-history自动生成历史表时,错误地同时将原UUID字段标记为
primary_key=True,又添加了history_id作为AutoField主键,违反数据库单主键规则,触发迁移错误。 - 手动修改的缺陷:你将
history_id改为IntegerField但未修正原UUID字段的primary_key=True,也未给history_id设置主键,导致历史表没有合法主键,simple-history无法正常写入历史记录。
修复步骤
方案一:修正自动生成的迁移文件
- 若已执行错误迁移,先回滚到添加
HistoricalRecords之前的版本:
(替换python manage.py migrate your_app_name 00XX_previous_migrationyour_app_name为你的应用名,00XX_previous_migration为添加历史记录前的迁移编号) - 删除错误迁移文件,重新生成迁移:
python manage.py makemigrations - 打开新生成的迁移文件,修改
HistoricalDataSeriesModel的字段定义:- 移除原UUID字段(
id)的primary_key=True参数,保留db_index=True - 确保
history_id保持AutoField(primary_key=True)作为唯一主键
修改后的字段示例:
fields=[ ('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')), ('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')), ('id', model_utils.fields.UUIDField(db_index=True, default=uuid.uuid4, editable=False)), ('name', models.CharField(max_length=255)), ... ('history_id', models.AutoField(primary_key=True, serialize=False)), ('history_date', models.DateTimeField(db_index=True)), ('history_change_reason', models.CharField(max_length=100, null=True)), ('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)), ('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)), ] - 移除原UUID字段(
- 执行迁移:
python manage.py migrate
方案二:通过模型配置指定历史主键
直接在DataSeriesModel中配置HistoricalRecords,明确指定历史表的主键字段,避免自动生成错误:
from django.db import models from model_utils.fields import AutoCreatedField, AutoLastModifiedField, UUIDField from simple_history.models import HistoricalRecords import uuid class DataSeriesModel(models.Model): created = AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created') modified = AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified') id = UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False) name = models.CharField(max_length=255) # 其他字段... # 配置历史记录,指定history_id为主键 history = HistoricalRecords(history_id_field=models.AutoField(primary_key=True))
然后重新生成并执行迁移:
python manage.py makemigrations python manage.py migrate
验证历史记录生成
完成修复后,执行以下操作验证:
- 新增一条
DataSeriesModel记录,检查HistoricalDataSeriesModel.objects.all()是否有对应创建记录 - 修改该记录,检查是否生成变更记录
- 删除该记录,检查是否生成删除记录
内容的提问来源于stack exchange,提问作者zacniewski
相关产品推荐
相关产品推荐

