2014-05-03 116 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

相關問題