【问题标题】:'ON CONFLICT' error for new single insert through Django admin to postgres通过 Django admin 到 postgres 的新单个插入的“ON CONFLICT”错误
【发布时间】:2021-04-27 04:26:38
【问题描述】:

今天,我第一次在尝试通过 Django 管理员向我的 postgres 数据库插入新条目时遇到“ON CONFLICT”错误:

ignored_wrapper_args
(False,
 {'connection': <django.db.backends.postgresql.base.DatabaseWrapper object at 0x7f0bb08e3d90>,
  'cursor': <django.db.backends.postgresql.base.CursorDebugWrapper object at 0x7f0bb094ab50>})
params
(3351, 48, 3351, 212, 3351, 31)
self
<django.db.backends.postgresql.base.CursorDebugWrapper object at 0x7f0bb094ab50>
sql
('INSERT INTO "ktab_entry_tags" ("entry_id", "tag_id") VALUES (%s, %s), (%s, '
 '%s), (%s, %s) ON CONFLICT DO NOTHING')

3351 是 自动分配给条目的 ID(如果条目被接受)。 48、212 和 31 是我要在此条目上放置的 3 个标签的 ID。

我已经使用这个我创建的博客应用程序将近 3 年了。我不仅以前从未遇到过这个错误,而且对我来说没有意义。每个条目都有一个唯一的 id。因此,很难想象由于 entry_id、tag_id 和 entry_tag_id 的组合重复而发生冲突的情况。因此,任何此类约束都是多余且不必要的。

但看起来我确实拥有它:

ktab.public.ktab_entry_tags.ktab_entry_tags_entry_id_tag_id_0900d285_uniq(entry_id, tag_id)

ktab.public.ktab_entry_tags.ktab_entry_tags_entry_id_tag_id_0900d285_uniq(entry_id, tag_id) UNIQUE

如果第二个是唯一的,为什么两个都以'_uniq'结尾?

我也有两个:

ktab.public.ktab_entry_tags.ktab_entry_tags_pkey(id)

ktab.public.ktab_entry_tags.ktab_entry_tags_pkey(id) UNIQUE

请注意,这是 Django 为我创建的中间表,因为它是多对多字段。我开始每人删除一个,但我没有,因为我仍然不明白这是如何导致或解决我的问题 - 或者为什么它现在才出现。

根据 PyCharm / DataGrip,最后一个成功的条目的 id 为 3350。因此,我可以看到与 tag_ids=212、48 和 31 的 entry_id=3351 的新条目没有冲突。我有数据库工具和 SQL 插件。

过滤: tag_id = '48' AND tag_id = '212' AND tag_id = '31' 什么都没有,包括没有错误!

entry_id = '3351' 一样的

entry_id = '3350' 正如预期的那样,得到 3 个结果。 3 个标签各有一个,每个标签都有自己的 ktab_entry_tags id,但都具有相同的 entry_id:

3102,3350,86
3101,3350,13
3100,3350,8

我不太了解“ignored_wrapper_args”,请参阅https://github.com/django/django/blob/main/django/db/backends/utils.py。我猜这是 False 因为它确实有联系?

我看到了这个:Postgres: INSERT if does not exist already 但这不是并发操作。我正在尝试通过 Django 管理员添加一个条目。

但是,我在回溯中也看到了 bulk_create,这对于单个插入没有意义,尤其是 "ignore_conflicts=ignore_conflicts":

/home/malikarumi/.virtualenvs/chronic_all/lib/python3.9/site-packages/django/db/models/query.py, line 506, in bulk_create
...
            if objs_without_pk:
                fields = [f for f in fields if not isinstance(f, AutoField)]
                returned_columns = self._batched_insert( …
                    objs_without_pk, fields, batch_size, ignore_conflicts=ignore_conflicts,
                )
                if connection.features.can_return_rows_from_bulk_insert and not ignore_conflicts:
                    assert len(returned_columns) == len(objs_without_pk)
                for obj_without_pk, results in zip(objs_without_pk, returned_columns):
                    for result, field in zip(results, opts.db_returning_fields):

这个错误可能是因为该条目还没有 ID?我也认为这没有道理。

感谢您的帮助。

ps

在最后一秒我决定检查版本,得到了这个:

PostgreSQL 9.4.26 on x86_64-pc-linux-gnu (Ubuntu 9.4.26-2.pgdg18.04+1), compiled by gcc (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0, 64-bit

看到我的 Postgres 多大了,我有点害怕。我实际上安装了较新的版本,但正如我所说,我已经使用这个应用程序三年了,没有任何问题。在等待您的回答时,我将看到有关升级和删除旧版本的信息。但我也读到“ON CONFLICT”是从 9.5 开始的,那我们该如何解释呢?

Python 3.9.4 Django 3.1.7 Ubuntu 20.04.2 LTS

【问题讨论】:

    标签: python django postgresql


    【解决方案1】:

    我不知道是否有很多人遇到这个问题,但归结为自己造成的语法错误。当 Django/Postgres 确定存在冲突时,“DO NOTHING”是 IntegrityError 的替代方法。但随后他们会采取额外的步骤将该字符串附加到 INSERT 的末尾,将其视为语法错误!更糟糕的是,至少在我的情况下,没有冲突!底线,我注释掉了以下几行,一切恢复正常:

    site-packages/django/db/models/sql/compiler.py 的第 1382-3 行:

    if ignore_conflicts_suffix_sql
    result.append(ignore_conflicts_suffix_sql)
    

    在第 284-5 行

    site-packages/django/db/backends/postgresql/operations.py

    def ignore_conflicts_suffix_sql(self, ignore_conflicts=None):
        return 'ON CONFLICT DO NOTHING' if ignore_conflicts else 
        super().ignore_conflicts_suffix_sql(ignore_conflicts)
    

    【讨论】:

      猜你喜欢
      • 2016-04-26
      • 1970-01-01
      • 1970-01-01
      • 2022-01-23
      • 2018-09-10
      • 1970-01-01
      • 2019-02-02
      • 2013-10-28
      • 1970-01-01
      相关资源
      最近更新 更多