2009-11-27 13 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

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

相关问题