2009-11-27 14 views
0

在Django,我試圖做這樣的事情:爲什麼在將其添加到另一個模型之前需要保存此模型?

# if form is valid ... 
article = form.save(commit=False) 
article.author = req.user 

product_name = form.cleaned_data['product_name'] 
try: 
    article.product = Component.objects.get(name=product_name) 
except: 
    article.product = Component(name=product_name) 

article.save() 
# do some more form processing ... 

但隨後它告訴我:

在列 「的product_id」

空值違反非空約束

但我不明白爲什麼這是一個問題。當調用article.save()時,它應該能夠創建產品,然後(並生成一個id)。

我可以在except塊使用此代碼解決這個問題:

product = Component(name=product_name) 
product.save() 
article.product = product 

但是這涉及到我的理由是,因爲如果article.save()失敗,將已經創建了一個新組件/產品。我希望他們一起成功或失敗。

有沒有一種很好的方法來解決這個問題?

+1

注意:article.product = Component.objects.create(name = product_name)有點整齊 – michael

+0

@michael:哦!不知道我能做到這一點。這至少有點好一點。 – mpen

回答

1

你可以解決這個問題,通過使用:

target_product, created_flag = Component.objects.get_or_create(name=product_name) 
article.product = target_product 

,因爲我敢肯定get_or_create()將設置一個對象的ID(如果有)來創建一個。

或者,如果您不介意商品表上的空FK關係,則可以將null=True添加到定義中。

+0

如果我不在乎'created_flag'怎麼辦?有沒有一些python syntaxy的優點讓我可以忽略它?也許是一個逗號,但沒有第二個val? – mpen

+0

下劃線很常見: target_product,_ = Component.object.get_or_create(...) 我使用雙下劃線,我爲i18n函數保留單下劃線。 –

+0

下劃線相當難看,你不覺得嗎?正如你指出的那樣,如果你使用django i18n,那就很危險。在給旗子一個毫無意義的名字上沒有性能好處,即不需要的變量仍然被創建,所以我會給它一個有意義的名字,說實話(和明確的)。 – thepeer

4

Django ManyToManyField的工作方式是創建一個額外的表。所以說你有兩個型號,ModelA和ModelB。如果你沒有...

ModelA.model_b = models.ManyToManyField(ModelB) 

什麼Django的實際執行幕後爲它創建一個表... app_modela_modelb有三列:idmodel_a_idmodel_b_id

把你的想法留在你的腦海裏。關於保存ModelB,Django在保存之前不會爲其分配ID。您可以從技術上手動爲其分配一個ID並避免此問題。看來你讓django處理完全可以接受的東西。

Django在做M2M時遇到了問題。爲什麼?如果ModelB還沒有id,M2M表格中的model_b_id列會出現什麼情況? null product_id的錯誤很可能是M2M字段上的空約束錯誤,而不是ModelB記錄ID。

如果您希望他們「一起成功」或「一起失敗」,或許是時候研究交易。例如,您將整個事件包裝在事務中,並在發生部分故障時進行回滾。我在這方面並沒有做很多工作,所以希望別人能夠在這方面提供幫助。

+0

+1對於交易 – Davy8

+0

看起來很好記錄http://docs.djangoproject.com/en/dev/topics/db/transactions/ – michael

+0

我應該刪除關於m2m的評論。組件是*不是* m2m字段。它只是一個'ForeignKey'。這並不能真正回答爲什麼在文章之前無法創建組件。我提出這個問題的原因是因爲它通常與表單一起工作。當你執行'modelForm.save()'時,它會創建進程中需要的任何其他對象,並將它們全部保存(除非你有'commit = False')。無論如何,我猜「交易」是一個好的選擇。 – mpen

1

在交易中包含代碼段幾乎沒有什麼價值,因爲您應該閱讀the Django documentation以獲得良好的理解。

+0

你說得對,但我一直在尋找一種根本不涉及交易的解決方案。交易文件看起來很清楚。 – mpen

+0

避免交易方式的任何理由? –

相關問題