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

从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、排除系统模型等变体),均未解决问题。

可能原因

  1. SQLite与PostgreSQL约束检查差异:SQLite对唯一性约束的检查更宽松(如允许隐性重复、大小写不敏感),PostgreSQL严格执行约束,导致原SQLite中隐性存在的重复数据在PostgreSQL中暴露。
  2. Fixture导出冗余数据:dumpdata可能因关联关系、ContentType自动生成等原因,导出了重复的DIN_STATUS条目。
  3. 数据库残留数据:迁移前PostgreSQL数据库未完全清空,残留数据与导入的fixture冲突。
  4. 导入顺序问题: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 03:15:50