2015-06-11 69 views
7

我在單元測試中遇到了數據庫問題。我認爲這與我使用TestCase和setUpData的方式有關。Django測試:postgres上的setUpTestData引發:「重複鍵值違反了唯一約束」

當我嘗試建立我的測試數據與特定的值,測試拋出以下錯誤:

django.db.utils.IntegrityError: duplicate key value violates unique constraint 

... 

psycopg2.IntegrityError: duplicate key value violates unique constraint "InventoryLogs_productgroup_product_name_48ec6f8d_uniq" 
DETAIL: Key (product_name)=(Almonds) already exists. 

我改變了我所有的主鍵,它似乎運行良好。它似乎不影響任何測試。

但是,我擔心我做錯了什麼。當它第一次發生時,我扭轉了我的應用程序大約一小時的工作量(沒有太多的代碼),這糾正了問題。

然後,當我寫回更改時,同樣的問題又出現了。 TestCase被粘貼在下面。這個問題似乎發生在我添加sortrecord項目後,但與上面的項目相對應。

我不想繼續在我的測試中更改主鍵和URL,所以如果任何人看到我使用這種方式的錯誤,請幫助我。謝謝!

的TestCase

class DetailsPageTest(TestCase): 


@classmethod 
def setUpTestData(cls): 

    cls.product1 = ProductGroup.objects.create(
         product_name="Almonds" 
         ) 
    cls.variety1 = Variety.objects.create(
         product_group = cls.product1, 
         variety_name = "non pareil", 
         husked = False, 
         finished = False, 
         ) 

    cls.supplier1 = Supplier.objects.create(
         company_name = "Acme", 
         company_location = "Acme Acres", 
         contact_info = "Call me!" 
         ) 

    cls.shipment1 = Purchase.objects.create(
         tag=9, 
         shipment_id=9999, 
         supplier_id = cls.supplier1, 
         purchase_date='2015-01-09', 
         purchase_price=9.99, 
         product_name=cls.variety1, 
         pieces=99, 
         kgs=999, 
         crackout_estimate=99.9 
         ) 
    cls.shipment2 = Purchase.objects.create(
         tag=8, 
         shipment_id=8888, 
         supplier_id=cls.supplier1, 
         purchase_date='2015-01-08', 
         purchase_price=8.88, 
         product_name=cls.variety1, 
         pieces=88, 
         kgs=888, 
         crackout_estimate=88.8 
         ) 
    cls.shipment3 = Purchase.objects.create(
         tag=7, 
         shipment_id=7777, 
         supplier_id=cls.supplier1, 
         purchase_date='2014-01-07', 
         purchase_price=7.77, 
         product_name=cls.variety1, 
         pieces=77, 
         kgs=777, 
         crackout_estimate=77.7 
         ) 

    cls.sortrecord1 = SortingRecords.objects.create(
         tag=cls.shipment1, 
         date="2015-02-05", 
         bags_sorted=20, 
         turnout=199, 
         ) 

    cls.sortrecord2 = SortingRecords.objects.create(
         tag=cls.shipment1, 
         date="2015-02-07", 
         bags_sorted=40, 
         turnout=399, 
         ) 
    cls.sortrecord3 = SortingRecords.objects.create(
         tag=cls.shipment1, 
         date='2015-02-09', 
         bags_sorted=30, 
         turnout=299, 
         ) 

模式

from datetime import datetime 

from django.db import models 
from django.db.models import Q 


class ProductGroup(models.Model): 
    product_name = models.CharField(max_length=140, primary_key=True) 

    def __str__(self): 
     return self.product_name 

    class Meta: 
     verbose_name = "Product" 

class Supplier(models.Model): 
    company_name = models.CharField(max_length=45) 
    company_location = models.CharField(max_length=45) 
    contact_info = models.CharField(max_length=256) 

    class Meta: 
     ordering = ["company_name"] 

    def __str__(self): 
     return self.company_name 

class Variety(models.Model): 
    product_group = models.ForeignKey(ProductGroup) 
    variety_name = models.CharField(max_length=140) 
    husked = models.BooleanField() 
    finished = models.BooleanField() 
    description = models.CharField(max_length=500, blank=True) 

    class Meta: 
     ordering = ["product_group_id"] 
     verbose_name_plural = "Varieties" 

    def __str__(self): 
     return self.variety_name 


class PurchaseYears(models.Manager): 

    def purchase_years_list(self): 
     unique_years = Purchase.objects.dates('purchase_date', 'year') 
     results_list = [] 
     for p in unique_years: 
      results_list.append(p.year) 
     return results_list 


class Purchase(models.Model): 
    tag = models.IntegerField(primary_key=True) 
    product_name = models.ForeignKey(Variety, related_name='purchases') 
    shipment_id = models.CharField(max_length=24) 
    supplier_id = models.ForeignKey(Supplier) 
    purchase_date = models.DateField() 
    estimated_delivery = models.DateField(null=True, blank=True) 
    purchase_price = models.DecimalField(max_digits=6, decimal_places=3) 
    pieces = models.IntegerField() 
    kgs = models.IntegerField() 
    crackout_estimate = models.DecimalField(max_digits=6,decimal_places=3, null=True) 
    crackout_actual = models.DecimalField(max_digits=6,decimal_places=3, null=True) 
    objects = models.Manager() 
    purchase_years = PurchaseYears() 
    # Keep manager as "objects" in case admin, etc. needs it. Filter can be called like so: 
    # Purchase.objects.purchase_years_list() 
    # Managers in docs: https://docs.djangoproject.com/en/1.8/intro/tutorial01/ 

    class Meta: 
     ordering = ["purchase_date"] 

    def __str__(self): 
     return self.shipment_id 

    def _weight_conversion(self): 
     return round(self.kgs * 2.20462) 
    lbs = property(_weight_conversion) 

class SortingModelsBagsCalulator(models.Manager): 

    def total_sorted(self, record_date, current_set): 
     sorted = [SortingRecords['bags_sorted'] for SortingRecords in current_set if 
        SortingRecords['date'] <= record_date] 
     return sum(sorted) 


class SortingRecords(models.Model): 
    tag = models.ForeignKey(Purchase, related_name='sorting_record') 
    date = models.DateField() 
    bags_sorted = models.IntegerField() 
    turnout = models.IntegerField() 
    objects = models.Manager() 

    def __str__(self): 
     return "%s [%s]" % (self.date, self.tag.tag) 

    class Meta: 
     ordering = ["date"] 
     verbose_name_plural = "Sorting Records" 

    def _calculate_kgs_sorted(self): 
     kg_per_bag = self.tag.kgs/self.tag.pieces 
     kgs_sorted = kg_per_bag * self.bags_sorted 
     return (round(kgs_sorted, 2)) 
    kgs_sorted = property(_calculate_kgs_sorted) 

    def _byproduct(self): 
     waste = self.kgs_sorted - self.turnout 
     return (round(waste, 2)) 
    byproduct = property(_byproduct) 

    def _bags_remaining(self): 
     current_set = SortingRecords.objects.values().filter(~Q(id=self.id), tag=self.tag) 
     sorted = [SortingRecords['bags_sorted'] for SortingRecords in current_set if 
        SortingRecords['date'] <= self.date] 
     remaining = self.tag.pieces - sum(sorted) - self.bags_sorted 
     return remaining 
    bags_remaining = property(_bags_remaining) 

編輯

它也不能與整數,像這樣。

django.db.utils.IntegrityError: duplicate key value violates unique constraint "InventoryLogs_purchase_pkey" 
DETAIL: Key (tag)=(9) already exists. 

UDPATE

所以我應該提到這較早,但我完全忘了。我有兩個使用相同數據的單元測試文件。只是爲了踢球,我在setUpTestData()的兩個實例中將主鍵與不​​同的值進行了匹配,果然,我得到了同樣的錯誤。

這兩個設置在我向其中的一個添加更多數據之前並行工作。現在看來,他們需要不同的價值觀。我想你只能使用重複數據這麼久了。

+1

爲什麼你不讓分貝選擇了IDS? –

+0

你應該把你的模型放在你的文章中。 'SortingRecords.tag'可能是唯一的嗎? –

+0

哈。這可能是明智的。我想我最初是這樣設置的,因爲我想阻止多個標籤,產品等的出現。這是當時最明顯的方式,但我確信有一個更明智的方法來做到這一點。 –

回答

0

所有的測試數據串,我發現了問題,因爲在這個問題的底部指出。

從我所知道的情況來看,數據庫並不喜歡我在兩種不同測試的setUpTestData()方法中使用重複數據。在第二個測試中更改主鍵值可以糾正問題。

0

您提供的日誌狀態爲DETAIL: Key (product_name)=(Almonds) already exists。你在你的數據庫中驗證過嗎?

爲了避免這樣的錯誤在未來,你應該通過前綴test_

+0

實際上,杏仁確實存在作爲產品名稱並且有一段時間。但是,這從來都不是問題。無論如何,測試總是能夠在TestCase下成功運行。此外,它給了我同樣的錯誤標籤,這是不重複在數據庫中,但(假設)與每個測試創建,然後刪除。我應該重新迭代,這個神祕的數據實際上並不在測試中出現。 –

+0

您最近使用過'manage.py migrate'嗎?我認爲它創建了一個用作測試起點的數據庫快照 –

+0

是的,我實際上搞砸了遷移很糟糕,這就是爲什麼我顛倒了一堆工作。顯然這種努力並未解決問題。無論如何,我試圖爲你重新制造一個錯誤,但這個問題似乎已經消失。我沒有足夠的代表upvote,但感謝您的幫助。 –

相關問題