2014-05-03 81 views
2

我收到以下错误:如何解决django.db.utils.IntegrityError:重复键值违反唯一约束?

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的大多数问题几乎都不可避免地提到了南方。我需要南方还是其他地方?我只是想在不安装迁移的情况下做一个快速而肮脏的测试。

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

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

我发现下面的blog post,似乎解释get_or_create()打破,当你使用 'auto_now_add =真'。现在最大的问题是如何使用auto_now_add而不破坏get_or_create()?

+0

你“获得”有'lat'和坐标'lon'如你所指定的,*以及*具有'created_by'和'modified_by'作为'self._user'。难道是在数据库中存在一个具有相同'lat'和'lon'但是不同的'created_by'或'modified_by'的坐标吗? – univerio

+0

我用来填充数据库的脚本只有一个它分配的用户。即使用户不同,也不要紧,因为(经纬度)对必须独立于与加法相关的用户而独立。 –

回答

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调用。然后,如果在指定的lat,lon的数据库中没有记录,它将创建一个新记录,其默认值为lat,lon,这显然不是自动生成的,您将获得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, 
    ) 
) 

作为唯一索引由(看着从错误索引名),你应该使用所有的人都在get_or_create过滤器列latloncreated_by的。

+0

我完全添加了上面显示的默认参数,并且完整性错误仍然存​​在。 –

+0

我没有意识到我需要将所有的坐标字段放在默认字典中。坐标模型包含另一个字段'date_created = models.DateTimeField(auto_now_add = True)' 我发现以下博客帖子似乎解释了当您使用'auto_now_add = True'时,get_or_create()会中断。最大的问题是我如何使用auto_now_add而不破坏get_or_create()? –

+0

由于'date_created'是自动填充的,所以你不需要把它放在'defaults'中。由于唯一索引由'lat','lon'和'created_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 = {...})' – warvariuc

相关问题