从SQLite迁移至PostgreSQL时出现Psycopg2唯一键约束冲突
解决SQLite迁移PostgreSQL时JSON Fixture唯一键约束冲突问题
问题描述
从SQLite迁移至PostgreSQL,通过JSON fixtures导出导入数据时,持续触发唯一键约束冲突错误:
django.db.utils.IntegrityError: Problem installing fixture '/PATH/wcontenttypes.json': Could not load MyApp.DIN_STATUS(pk=1): duplicate key value violates unique constraint "MyApp_din_status_DSP_id_EA_id_1c1c3e96_uniq" DETAIL: Key ("DSP_id", "EA_id")=(542, 20324) already exists.
删除报错行后,后续行仍触发同类错误,且已确认原SQLite数据无重复、引用行存在。已测试三种迁移方案(含删除迁移文件、--run-syncdb、排除系统模型等变体),均未解决问题。
可能原因
- SQLite与PostgreSQL约束检查差异:SQLite对唯一性约束的检查更宽松(如允许隐性重复、大小写不敏感),PostgreSQL严格执行约束,导致原SQLite中隐性存在的重复数据在PostgreSQL中暴露。
- Fixture导出冗余数据:
dumpdata可能因关联关系、ContentType自动生成等原因,导出了重复的DIN_STATUS条目。 - 数据库残留数据:迁移前PostgreSQL数据库未完全清空,残留数据与导入的fixture冲突。
- 导入顺序问题:fixture中模型数据的导入顺序不合理,导致依赖模型未完全导入时,重复插入关联数据。
解决方案
1. 检查并清理Fixture中的重复数据
- 用文本搜索工具在fixture文件中查找冲突键值对
"DSP_id": 542, "EA_id": 20324,确认是否存在多个DIN_STATUS条目。 - 若存在重复,手动删除冗余条目后重新导入。
2. 优化Dumpdata参数导出数据
使用更严谨的参数导出fixture,避免系统模型和冗余数据干扰:
# 从SQLite导出时,使用natural主键/外键,排除系统模型 python manage.py dumpdata --natural-primary --natural-foreign \ --exclude contenttypes --exclude auth.permission \ --exclude admin.logentry --exclude sessions.session \ --indent 4 > fixture.json
3. 重置PostgreSQL数据库后重新导入
确保数据库为全新状态,避免残留数据冲突:
# 切换至PostgreSQL环境后,重置数据库 dropdb your_db_name createdb your_db_name # 重新生成迁移并执行 python manage.py makemigrations python manage.py migrate # 导入fixture python manage.py loaddata fixture.json -v3
4. 调整导入顺序,分模型导入
若存在依赖关系,先导入被依赖模型的数据,再导入冲突模型:
# 先导出并导入DSP和EA模型数据 python manage.py dumpdata MyApp.DSP MyApp.EA > dependencies.json python manage.py loaddata dependencies.json # 再导出并导入DIN_STATUS及其他模型 python manage.py dumpdata --exclude MyApp.DSP --exclude MyApp.EA ... > rest_data.json python manage.py loaddata rest_data.json
5. 验证模型唯一性约束定义
检查DIN_STATUS模型的唯一性约束定义,确保SQLite与PostgreSQL行为一致:
- 若使用
unique_together,替换为UniqueConstraint(Django 2.2+推荐):
# models.py class DIN_STATUS(models.Model): DSP = models.ForeignKey(DSP, on_delete=models.CASCADE) EA = models.ForeignKey(EA, on_delete=models.CASCADE) # ...其他字段 class Meta: constraints = [ models.UniqueConstraint(fields=['DSP', 'EA'], name='unique_dsp_ea') ]
- 若涉及字符串字段的唯一性,确认是否需要添加
db_collation='C'使PostgreSQL区分大小写(与SQLite默认行为一致)。
内容的提问来源于stack exchange,提问作者SaFteiNZz
相关产品推荐
相关产品推荐

