如何修复django.db.utils.IntegrityError:重复键值违反了唯一约束?

时间:2014-05-03 03:38:29

标签: python mysql django postgresql psycopg2

我收到以下错误:

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工作正常。南没有安装。

我运行了一个脚本(适用于MySQL)。该脚本循环通过GPS文件并将lat / lon数据保存在坐标表中。

_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的大多数问题几乎不可避免地提到南方。我需要南方,还是其他什么东西在这里?我只是想在不安装迁移的情况下进行快速而肮脏的测试。

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

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

我发现以下blog post似乎解释了当你使用'auto_now_add = True'时get_or_create()会中断。现在最大的问题是如何使用auto_now_add而不破坏get_or_create()?

2 个答案:

答案 0 :(得分:2)

你错过了defaults的论点 get_or_create致电。然后,如果数据库中没有指定lat lon的记录,它将使用默认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(查看错误中的索引名称)组成,因此您应该在{{的过滤器中使用所有这些列1}}。

答案 1 :(得分:2)

这回答了我的问题。

_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()的{​​{1}}部分会尝试将数据库中的Decimal值与我提供的浮点值进行比较。类型被更强烈地解释,并且在比较期间不会将float转换为Decimal。

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

get_or_create()

如果django能够产生像{Decimal}lat {float}group[lat]

这样的明确错误,那就太好了