代码之家  ›  专栏  ›  技术社区  ›  senderle

Django是否提供任何内置方式来更新PostgreSQL自动增量计数器?

  •  3
  • senderle  · 技术社区  · 7 年前

    我正在将Django网站从MySQL迁移到PostgreSQL。数据量不是很大,所以我采用了一种非常简单的方法:我只使用了内置的Django serialize and deserialize 创建JSON记录的例程,然后将它们加载到新实例中,循环对象,并将每个对象保存到新数据库中。

    这很好地工作,但有一个小问题:加载所有记录后,我遇到了一个 IntegrityError 当我加载旧记录后尝试添加新数据时。与MySQL autoincrement ID字段相当的Postgres是一个串行字段,但当显式指定ID值时,串行字段的内部计数器不会递增。结果,Postgres试图从1开始对记录进行编号——已经使用了——导致违反约束。(这是Django的一个已知问题,标记为 wontfix .)

    有相当多的问题和答案与此相关,但似乎没有一个答案能够直接在Django的背景下解决这个问题。 This answer 给出了更新计数器需要运行的查询的示例,但我尽量避免在可能的情况下进行显式查询。我 能够 只需在保存之前删除ID字段,并让Postgres自己进行编号,但有 ForeignKey 在这种情况下会被破坏的引用。其他一切都很完美!

    如果Django提供了一个能够智能地处理任何边缘情况的例程,那就太好了。(这不会修复该漏洞,但它将允许开发人员以一致且正确的方式解决它。)我们真的需要使用原始查询来解决这个问题吗?这看起来太野蛮了。

    如果真的没有这样的例行程序,我只需要做下面这样的事情,直接运行上面链接的答案中建议的查询。但在这种情况下,我很想听听这种方法的任何潜在问题,或者关于我可能做错了什么的任何其他信息。例如,我应该修改记录以使用UUID吗 this suggests ?

    以下是原始方法(经过编辑以反映我实际完成的工作的简化版本)。非常接近 Pere Picornell 他的回答是,但在我看来,他的回答更有力。

    table = model._meta.db_table
    cur = connection.cursor()
    cur.execute(
        "SELECT setval('{}_id_seq', (SELECT max(id) FROM {}))".format(table, table)
    )
    
    2 回复  |  直到 6 年前
        1
  •  1
  •   Pere Picornell    7 年前

    关于争论:我的案例是一次性迁移,我的决定是在完成每个表的迁移后立即运行这个函数,尽管您可以在怀疑完整性可能会被破坏的任何时候调用它。

        def synchronize_last_sequence(model):
            #  Postgresql aut-increments (called sequences) don't update the 'last_id' value if you manually specify an ID.
            #  This sets the last incremented number to the last id
            sequence_name = model._meta.db_table+"_"+model._meta.pk.name+"_seq"
            with connections['default'].cursor() as cursor:
                cursor.execute(
                    "SELECT setval('" + sequence_name + "', (SELECT max(" + model._meta.pk.name + ") FROM " +
                    model._meta.db_table + "))"
                )
            print("Last auto-incremental number for sequence "+sequence_name+" synchronized.")
    

    我使用了你在问题中提出的SQL查询。 找到你的帖子很有用。非常感谢。

    它应该适用于自定义PK,但不适用于多字段PK。

        2
  •  1
  •   schillingt    7 年前

    一种选择是使用 natural keys 在序列化和反序列化期间。这样,当您将其插入PostgreSQL时,它将自动增加主键字段,并使所有内容保持内联。

    这种方法的缺点是,对于不包含id的每个模型,需要有一组唯一的字段。