【问题标题】:IntegrityError duplicate key value violates unique constraint - django/postgresIntegrityError 重复键值违反唯一约束 - django/postgres
【发布时间】:2012-06-20 20:04:03
【问题描述】:

我正在跟进question that I asked earlier,在该question that I asked earlier 中,我试图寻求从愚蠢/写得不好的mysql 查询到postgresql 的转换。我相信我成功了。无论如何,我使用的是手动从 mysql 数据库移动到 postgres 数据库的数据。我正在使用如下所示的查询:

  UPDATE krypdos_coderound cru

  set is_correct = case 
      when t.kv_values1 = t.kv_values2 then True 
      else False 
      end

  from 
  
  (select cr.id, 
    array_agg(
    case when kv1.code_round_id = cr.id 
    then kv1.option_id 
    else null end 
    ) as kv_values1,

    array_agg(
    case when kv2.code_round_id = cr_m.id 
    then kv2.option_id 
    else null end 
    ) as kv_values2

    from krypdos_coderound cr
     join krypdos_value kv1 on kv1.code_round_id = cr.id
     join krypdos_coderound cr_m 
       on cr_m.object_id=cr.object_id 
       and cr_m.content_type_id =cr.content_type_id 
     join krypdos_value kv2 on kv2.code_round_id = cr_m.id

   WHERE
     cr.is_master= False
     AND cr_m.is_master= True 
     AND cr.object_id=%s 
     AND cr.content_type_id=%s 

   GROUP BY cr.id  
  ) t

where t.id = cru.id
    """ % ( self.object_id, self.content_type.id)
  )

我有理由相信这很有效。然而,这又引出了一个新问题。尝试提交时,我从 django 收到一条错误消息:

IntegrityError at (some url): 
duplicate key value violates unique constraint "krypdos_value_pkey"

我查看了此处发布的一些回复,但还没有找到解决问题的方法(尽管相关问题已经引起了一些有趣的阅读)。我在我的日志中看到了这一点,这很有趣,因为我从不明确调用 insert-django 必须处理它:

   STATEMENT:  INSERT INTO "krypdos_value" ("code_round_id", "variable_id", "option_id", "confidence", "freetext")
   VALUES (1105935, 11, 55, NULL, E'') 
   RETURNING "krypdos_value"."id"

但是,尝试运行它会导致重复键错误。实际错误在下面的代码中抛出。

 # Delete current coding         CodeRound.objects.filter(object_id=o.id,content_type=object_type,is_master=True).delete()
  code_round = CodeRound(object_id=o.id,content_type=object_type,coded_by=request.user,comments=request.POST.get('_comments',None),is_master=True)
  code_round.save()
  for key in request.POST.keys():
    if key[0] != '_' or key != 'csrfmiddlewaretoken':
      options = request.POST.getlist(key)
      for option in options:
        Value(code_round=code_round,variable_id=key,option_id=option,confidence=request.POST.get('_confidence_'+key, None)).save()  #This is where it dies
  # Resave to set is_correct
  code_round.save()
  o.status = '3' 
  o.save(

我已经检查了序列等,它们似乎是有序的。在这一点上,我不确定该怎么做——我认为这是 django 的结果,但我不确定。任何反馈将不胜感激!

【问题讨论】:

  • 旁白:根据德摩根定律,您的条件key[0] != '_' or key != 'csrfmiddlewaretoken' 等同于not (key[0] == '_' and key == 'csrfmiddlewaretoken')。应该很容易看出,内部条件永远不满足,所以它相当于not (False),或者换句话说True。但是,为什么还要打扰if
  • python manage.py sqlsequencereset <app> | python manage.py dbshell
  • 这个先前的答案提供了更多的细节和主题:stackoverflow.com/questions/244243/…

标签: django postgresql duplicates unique-constraint database-integrity


【解决方案1】:

这发生在我身上——事实证明你需要在 Postgres 中重新同步你的主键字段。关键是SQL语句:

SELECT setval('tablename_id_seq', (SELECT MAX(id) FROM tablename)+1);

【讨论】:

  • 就是这样!我以为我已经解决了这个问题,但事实证明我重置了错误的值。
  • 我知道有很多人遇到过这个问题 - 很高兴你解决了它!
  • 我正要问@HackingLife,你是否知道更多关于为什么会发生这种情况......对我们来说,这是因为我们通过直接复制来同步来自不同数据库的所有数据(其中是 zaphod 在他的回答中提到的)。当我们停止这样做并开始直接使用主数据库时,添加新模型时主键序列没有增加,从而产生此错误。
  • 我在通过 SQL 脚本手动导入内容后遇到了同样的问题,一旦我回到 Flask 中的 UI 添加新项目,它就会出现问题。更新主键字段序列对我有用。感谢您的修复!
  • 哇.. 我正在使用 heroku,我不得不将数据库移到亚马逊 AWS RDS。我在 aws 导出和导入到一个新的 postgres db,出现了这个问题。是否将 id 序列重置为上面提到的所有表,它就像一个魅力。谢谢!
【解决方案2】:

这似乎是 MySQL 和 SQLite 后端和其他后端(如 Postgres、Oracle、...不要)。

There is a ticket describing the same issue。即使它被关闭为无效,它也提供了一个提示,即有一个 Django 管理命令来更新下一个可用的密钥。

显示 SQL 更新应用程序 MyApp 的所有下一个 id:

python manage.py sqlsequencereset MyApp

为了执行该语句,您可以将其作为 dbshel​​l 管理命令的输入。对于 bash,您可以键入:

python manage.py sqlsequencereset MyApp | python manage.py dbshell

管理命令的优点是抽象出底层数据库后端,因此即使稍后迁移到不同的后端也可以工作。

【讨论】:

    【解决方案3】:

    我的“库存”应用程序中有一个现有表,我想在 Django 管理中添加新记录,但出现此错误:

    重复键值违反唯一约束“inventory_part_pkey” 详细信息:键 (part_id)=(1) 已存在。

    如前所述,我运行下面的代码来获取重置 id-s 的 SQL 命令:

    python manage.py sqlsequencereset inventory
    

    python manage.py sqlsequencereset inventory | python manage.py dbshell 连接到外壳不起作用

    • 所以我复制了生成的原始 SQL 命令
    • 然后为 postgreSQL 打开 pgAdmin3 https://www.pgadmin.org 并打开我的数据库
    • 点击 6. 图标(执行任意 SQL 查询)
    • 复制了生成的语句

    在我的例子中,原始 SQL 命令是:

    BEGIN;
    SELECT setval(pg_get_serial_sequence('"inventory_signup"','id'), coalesce(max("id"), 1), max("id") IS NOT null) FROM "inventory_signup";
    SELECT setval(pg_get_serial_sequence('"inventory_supplier"','id'), coalesce(max("id"), 1), max("id") IS NOT null) FROM "inventory_supplier";
    COMMIT;
    

    按 F5 执行。

    这解决了所有问题。

    【讨论】:

    • 这个答案应该是你真正需要的答案——这是最正确的方法!
    【解决方案4】:

    除了 zapphods 回答:

    在我的情况下,索引确实不正确,因为我已经删除了所有迁移,并且在开发时数据库可能有 10-15 次,因为我没有处于迁移任何阶段。

    我在 finished_product_template_finishedproduct_pkey 上收到 IntegrityError

    重新索引表并重启runserver:

    我使用的是 pgadmin3,对于不正确的索引并抛出重复的键错误,我导航到 constraints 并重新索引。

    然后重新索引。

    【讨论】:

    • Reindex 对我不起作用,但是完全分析(还检查了冻结和分析选项)对我有用。我在桌子上没有任何序列或触发器,但我认为一些未完成的插入卡在某个地方,所以真空完全帮助。
    【解决方案5】:

    解决方案是您需要重新同步您的主键字段,正如“Hacking Life”所报告的那样,他编写了一个示例 SQL 代码,但正如“Ad N”所建议的那样,最好运行 Django 命令sqlsequencereset 来获取您可以复制并粘贴或使用其他命令运行的确切 SQL 代码。

    作为对这些答案的进一步改进,我建议您和其他读者不要复制和粘贴 SQL 代码,而是更安全地以这种方式从您的 python 代码中执行sqlsequencereset 生成的 SQL 查询(使用默认数据库):

    from django.core.management.color import no_style
    from django.db import connection
    
    from myapps.models import MyModel1, MyModel2
    
    
    sequence_sql = connection.ops.sequence_reset_sql(no_style(), [MyModel1, MyModel2])
    with connection.cursor() as cursor:
        for sql in sequence_sql:
            cursor.execute(sql)
    

    我使用 Python3.6Django 2.0PostgreSQL 10 测试了这段代码。

    【讨论】:

    【解决方案6】:

    如果你想重置你所有桌子上的PK,像我一样,你可以使用PostgreSQL recommended way

    SELECT 'SELECT SETVAL(' ||
           quote_literal(quote_ident(PGT.schemaname) || '.' || quote_ident(S.relname)) ||
           ', COALESCE(MAX(' ||quote_ident(C.attname)|| '), 1) ) FROM ' ||
           quote_ident(PGT.schemaname)|| '.'||quote_ident(T.relname)|| ';'
    FROM pg_class AS S,
         pg_depend AS D,
         pg_class AS T,
         pg_attribute AS C,
         pg_tables AS PGT
    WHERE S.relkind = 'S'
        AND S.oid = D.objid
        AND D.refobjid = T.oid
        AND D.refobjid = C.attrelid
        AND D.refobjsubid = C.attnum
        AND T.relname = PGT.tablename
    ORDER BY S.relname;
    

    运行此查询后,您需要执行查询的结果。我通常复制并粘贴到记事本中。然后我用SELECT;"替换"SELECT;。我复制并粘贴到 pgAdmin III 并运行查询。它重置数据库中的所有表。上面的链接提供了更多“专业”说明。

    【讨论】:

      【解决方案7】:

      如果您手动复制了数据库,您可能会遇到issue described here

      【讨论】:

        【解决方案8】:

        我遇到了这个错误,因为我以错误的方式将额外的参数传递给了 save 方法。

        对于遇到这种情况的任何人,请尝试使用以下命令强制更新:

        instance_name.save(..., force_update=True)
        

        如果您遇到无法同时传递 force_insertforce_update 的错误,那么您可能像我一样以错误的方式传递了一些自定义参数。

        【讨论】:

        • 这是 django 中一个不错的解决方案。从外壳只需导入您的模型类(如果您不使用 shell_plus),然后执行 MyModelClass.objects.first().save(force_update=True)
        • 在我的情况下,我不得不同时使用 force_insert 和 force_update,因为我已经覆盖了 save 方法并调用了 super 2 次。在第一次保存时,将 force_insert 设置为 True 并将 force_update 设置为 False。在第二个存储集 force_insert 为 False 和 force_update 为 True。
        【解决方案9】:

        您只需转到 pgAdmin III 并使用表名执行您的脚本:

        SELECT setval('tablename_id_seq', (SELECT MAX(id) FROM tablename)+1);
        

        【讨论】:

        • 这与接受的答案有何不同?
        【解决方案10】:

        我遇到了与 OP 相同的错误。

        我创建了一些 Django 模型,基于模型创建了一个 Postgres 表,并通过 Django Admin 向 Postgres 表添加了一些行。然后我摆弄了模型中的一些列(围绕 ForeignKeys 进行更改等),但忘记迁移更改。

        运行迁移命令解决了我的问题,考虑到上面的 SQL 答案,这是有道理的。

        要查看将应用哪些更改,而不实际应用它们:
        python manage.py makemigrations --dry-run --verbosity 3

        如果您对这些更改感到满意,请运行:
        python manage.py makemigrations

        然后运行:
        python manage.py migrate

        【讨论】:

          【解决方案11】:

          我遇到了类似的问题,但似乎没有任何效果。如果您需要数据(即在转储时不能排除它),请确保您已关闭(注释)任何 post_save 接收器。我认为数据会被导入,但由于这些,它会再次创建相同的模型。为我工作。

          【讨论】:

            【解决方案12】:

            基于Paolo Melchiorre's answer,我写了一个块作为函数,在任何.save()之前调用

            from django.db import connection
            def setSqlCursor(db_table):
                sql = """SELECT pg_catalog.setval(pg_get_serial_sequence('"""+db_table+"""', 'id'), MAX(id)) FROM """+db_table+""";"""
                with connection.cursor() as cursor:
                    cursor.execute(sql)
            

            【讨论】:

              【解决方案13】:

              这是正确的说法。大多数情况下,当我们插入带有 id 字段的行时会发生这种情况。

              SELECT setval('tablename_id_seq', (SELECT MAX(id) FROM tablename));
              

              【讨论】:

                【解决方案14】:

                这个问题大约是 9 年前提出的,很多人都给出了自己的解决方法。

                对我来说,我将unique=True 放在我的email 自定义模型字段中,但是在创建超级用户时我并没有要求email 是强制性的。

                现在创建超级用户后,我的电子邮件字段只是保存为空白或Null。现在这就是我创建和保存新用户的方式

                obj = mymodel.objects.create_user(username='abc', password='abc')
                obj.email = 'abc@abc.com'
                obj.save()
                

                它只是在第一行抛出了duplicate-key-value-violates 的错误,因为电子邮件默认设置为空,这与管理员用户相同。 Django 发现了重复项!!!

                解决方案

                • 选项 1:在创建任何用户时强制发送电子邮件(对于超级用户也是如此)
                • 选项 2:删除 unique=True 并运行迁移
                • 选项3:如果您不知道重复项在哪里,您可以删除该列,也可以使用python manage.py flush 清除数据库

                强烈建议您了解您的案例中发生错误的原因。

                【讨论】:

                  猜你喜欢
                  • 2020-03-27
                  • 2019-03-20
                  • 2020-05-28
                  • 2016-06-12
                  • 2016-11-27
                  • 2018-03-14
                  • 2012-12-31
                  • 2014-02-23
                  相关资源
                  最近更新 更多