2016-01-06 18 views
1

我在我的Django應用程序以下兩個型號:Django的相關領域總是拋出生產完整性錯誤只

class BaseModel(models.Model): 
    """ 
    Base model 
    """ 
    uuid = models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True) 
    created = models.DateTimeField(auto_now_add=True, null=True) 
    modified = models.DateTimeField(auto_now=True, null=True) 

    class Meta: 
     abstract = True 

class BaseBillingModel(BaseModel): 
    """ 
    Base billing model with owner field and real_owner method (may reffer to Customer or Profile) 
    """ 
    owner = models.UUIDField() # uuid of Profile OR Customer 

    @property 
    def real_owner(self): 
     if self.type == 'customer': 
      return Customer.objects.get(uuid=self.owner) 
     if self.type == 'user': 
      return Profile.objects.get(uuid=self.owner) 

    class Meta: 
     abstract = True 


class Invoice(BaseBillingModel): 
    type = models.CharField(_('Invoice type'), max_length=16,  choices=INVOICE_PAYMENT_TYPES, default='user') 
    title = models.CharField(_("Title"), max_length=128, default="") 
    description = models.CharField(_("Description"), max_length=512, default="") 
    paid = models.BooleanField(_("Paid"), default=False) 
    cost = models.DecimalField(_("Total cost"), decimal_places=2, max_digits=10, default=Decimal("0")) 
    public = models.BooleanField(default=True) 


    def mark_paid(self): 
     self.paid = True 
     self.save() 


class InvoiceItem(BaseModel): 
    invoice = models.ForeignKey(Invoice, null=True, blank=True) 
    cost = models.DecimalField(_("Cost"), decimal_places=2, max_digits=10, default=Decimal("0")) 
    quantity = models.IntegerField(_("Quantity"), default=1) 
    title = models.CharField(_("Title"), max_length=128, default="") 
    description = models.CharField(_("Description"), max_length=512, default="") 

它基本上是有許多發票項發票模型。 我使用formset動態地添加/刪除項目到發票。 當我發佈Web表單時,我遍歷項目並總計總成本,然後保存發票。

查看代碼:

if request.method == 'POST': 
    invoice_form = InvoiceForm(request.POST) 
    formset = InvoiceItemFormset(request.POST) 

    total_forms = int(request.POST.get('form-TOTAL_FORMS')) 

    for x in range(total_forms): 
     identifier = "form-{x}-DELETE".format(x=x) 
     if identifier in request.POST: 
      deleted_items.append(x) 


    if request.POST.get('type') == 'customer': 
     invoice_form.fields['owner_choice'].choices = [(o.uuid.urn[9:],o.company_name) for o in Customer.objects.filter()] 

    if invoice_form.is_valid() and formset.is_valid(): 
     invoice = invoice_form.save(commit=False) 
     invoice.owner = invoice_form.cleaned_data.get('owner_choice') 
     cost = Decimal(0) 
     for form in formset: 

      if form not in formset.deleted_forms: 
       item = form.save(commit=False) 
       item.invoice = invoice 
       item.save() 
       cost += item.cost * item.quantity 
     invoice.cost = cost 
     invoice.save() 

它工作在我的本地環境(MariaDB的)的罰款,發票被所有項目創建的。 然而,舞臺/生產服務器上它不,如果我使用MySQL的 PostgreSQL的重要 - 我總是得到這樣的錯誤: (PostgreSQL系統)

IntegrityError at /staff/billing/new_invoice 
insert or update on table "core_invoiceitem" violates foreign key constraint "core_invoiceit_invoice_id_165c623e80fbe59c_fk_core_invoice_uuid" 
DETAILS: Key (invoice_id)=(bb83ff7a-9428-458c-909f-6ab4fa24a1b3) is not present in table "core_invoice". 

我不知道我該怎麼解決這個問題。任何想法傢伙?

回答

0

在保存發票項目之前,您必須先保存它所引用的發票。此時,您的舞臺/製作服務器在保存發票項目之後但保存發票之前正在檢查外鍵約束,因此您會收到完整性錯誤。

由於您使用的是uuid字段,因此Python正在創建主鍵而不是數據庫。因此,您可以通過使用原子裝飾器來防止錯誤。當您使用atomic裝飾器時,數據庫會檢查原子塊末尾的外鍵約束,這時發票已被保存。

from django.db import transaction 

transaction.atomic() 
def my_view(request): 

如果不工作,你需要確保你已經保存發票(不commit=False)保存發票項目之前。您可以保存發票項目和發票表單(均以commit=False),計算成本,保存發票,最後保存發票項目。

+0

但我需要先在發票上設置總成本。我在發票模型(保存後)中發出了一個信號,該信號以總成本向發票所有者發送電子郵件。我可以在不觸發信號的情況下保存發票嗎? 另外,爲什麼它在我的本地數據庫上工作? – dease

+0

您可以在將發票保存到數據庫之前計算成本。聽起來MariaDB可能沒有檢查外鍵約束(例如MyISAM引擎沒有)。我沒有MariaDB的任何經驗,所以我不能告訴你爲什麼你沒有在你的開發環境中得到錯誤。如果你已經吸引了一個'save()'的信號,我不認爲你可以調用'save()'而不觸發它。 – Alasdair