【问题标题】:How do I fix django.db.utils.IntegrityError: duplicate key value violates unique constraint?如何修复 django.db.utils.IntegrityError:重复键值违反唯一约束?
【发布时间】:2014-06-19 20:04:20
【问题描述】:

我收到以下错误:

django.db.utils.IntegrityError: duplicate key value violates unique constraint "record_coordinates_lat_lon_created_by_id_key"
DETAIL:  Key (lat, lon, created_by_id)=(34.84000015258789, -111.80000305175781, 2) already exists.

背景:到目前为止,我一直在使用 MySQL 和 Django 1.4.3。现在我已经安装了 Postgres 9.3 和 Psycopg2 2.5.2。验证和 Syncdb 工作正常。未安装 South。

我运行了一个脚本(适用于 MySQL)。该脚本循环遍历 GPS 文件并将纬度/经度数据保存在坐标表中。

_coordinates, coordinates_created = Coordinates.objects.get_or_create(
    lat=round(group[u'lat'], Coordinates.max_decimal_places),
    lon=round(group[u'lon'], Coordinates.max_decimal_places),
    created_by=self._user,
    modified_by=self._user,
    date_created=datetime.now(),  # See Update 2 addition below.
)

我在模型定义中有一个unique_together = ('lat', 'lon', ) 约束。一些坐标是相同的(因此使用 get_or_create())。我发现自己摸不着头脑,因为它应该“获取”坐标而不是尝试“创建”新坐标。

这个网站上关于 Postgres 和 Django 的大多数问题几乎都不可避免地提到了 South。我需要South,还是这里发生了其他事情?我只是想在不安装迁移的情况下进行快速而肮脏的测试。

更新 1: 我尝试的其他方法是在 suggestion of another post 上的 Postgres 中运行:SELECT setval('django_content_type_id_seq', (SELECT MAX(id) FROM django_content_type));。错误仍然存​​在。

更新 2: 好的,我没有意识到我需要将所有坐标字段都放在默认字典中。坐标模型包含另一个字段 'date_created=models.DateTimeField(auto_now_add=True)'

我发现以下blog post 似乎可以解释当您使用“auto_now_add=True”时 get_or_create() 会中断。现在最大的问题是如何在不破坏 get_or_create() 的情况下使用 auto_now_add?

【问题讨论】:

  • 您正在“获取”具有您指定的latlon 的坐标,以及 具有created_bymodified_by 作为self._user .会不会是数据库中存在一个坐标,latlon 相同,但created_bymodified_by 不同?
  • 我用来填充数据库的脚本只有一个分配的用户。即使用户不同,也没有关系,因为 (lat, lon) 对必须是唯一的,与添加关联的用户无关。

标签: python mysql django postgresql psycopg2


【解决方案1】:

这回答了我的问题。

_coordinates, coordinates_created = Coordinates.objects.get_or_create(            
    lat=Decimal(group[u'lat'])._rescale(-Coordinates.max_decimal_places, 'ROUND_HALF_EVEN'),
    lon=Decimal(group[u'lon'])._rescale(-Coordinates.max_decimal_places, 'ROUND_HALF_EVEN'),
    created_by=self._user,
    modified_by=self._user,         
)

auto_nowauto_now_add 很好。事实证明,我所有的默认值都已经在模型上定义了。

问题在于,当我将 group[u'lat']group[u'lon'] 放入字典时,它们都被转换为浮点数。相比之下,latlon 都定义为DecimalFields()

使用 MySQL 时,我可以将这些浮点值与数据库的内容进行比较。但是,当我使用 Postgres 时,get_or_create()get() 部分会尝试将数据库中的 Decimal 值与我提供的浮点值进行比较。类型的解释更强,在比较过程中浮点数不会转换为小数。

在我的调试器中,我看到了:

{Decimal}lat
{float}group[lat]

如果 django 能产生像 TypeError: Can't compare Decimal with float. 这样的明确错误,那就太好了

【讨论】:

    【解决方案2】:

    您错过了 defaults 参数 get_or_create 打电话。然后,如果数据库中没有指定latlon 的记录,它将使用默认的latlon 创建一个新记录,这显然不是自动生成的,你会得到IntegrityError .

    _coordinates, coordinates_created = Coordinates.objects.get_or_create(
        lat=round(group[u'lat'], Coordinates.max_decimal_places),
        lon=round(group[u'lon'], Coordinates.max_decimal_places),
        created_by=self._user,
        defaults=dict(
            lat=round(group[u'lat'], Coordinates.max_decimal_places),
            lon=round(group[u'lon'], Coordinates.max_decimal_places),
            created_by=self._user,
            modified_by=self._user,
        )
    )
    

    由于唯一索引由latloncreated_by 列组成(从错误中查看索引名称),您应该在get_or_create 的过滤器中使用它们。

    【讨论】:

    • 我完全添加了默认参数,如上所示,完整性错误仍然存​​在。
    • 我没有意识到我需要将我的所有坐标字段都放在默认字典中。坐标模型包含另一个字段 'date_created=models.DateTimeField(auto_now_add=True)' 我发现以下博客文章似乎解释了当您使用 'auto_now_add=True' 时 get_or_create() 会中断。最大的问题是如何在不破坏 get_or_create() 的情况下使用 auto_now_add?
    • 由于date_created 是自动填充的,因此您无需将其放入defaults。由于唯一索引由latloncreated_by 列组成(从错误中查看索引名称),您应该在get_or_create 的过滤器中使用它们:Coordinates.objects.get_or_create(lat=round(group[u'lat'], coordinates.max_decimal_places),lon=round(group[u'lon'], Coordinates.max_decimal_places), created_by=self._user, defaults={...})
    • 我决定重新使用 MySQL 而不是 Postgres,因为我的原始代码在 MySQL 下运行良好。
    猜你喜欢
    • 2019-07-22
    • 2018-03-28
    • 2013-10-08
    • 2016-04-14
    • 2018-12-06
    • 2022-11-05
    • 2021-01-25
    • 2019-05-03
    • 2022-01-13
    相关资源
    最近更新 更多