2012-02-03 60 views
0

下面是简化的示例的什么,我想实现:手动保存的ModelForm相对外键

class Product(models.Model): 
    # some data, does not really matter 

class ProductAttributeValue(models.Model): 
    product = models.ForeignKey('Product') 

    value=models.CharField(_("value"),max_length=100) 

....

class ProductForm(forms.ModelForm): 

    def __init__(self,*args, **kwargs): 
     super(ProductForm, self).__init__(*args, **kwargs) 

     #Here, I am dynamically constructing and injecting attributes. 
     #my products have dynamic attributes 
     # the filled-in values of these attributes need to be saved as ProductAttributeValue instances 
     #... 


    def save(commit): 
     m = super(ProductForm, self).save(commit=False) 

     #looping thru my custom attributes and constructing instances 
     #to simplify I will just put one example 
     attr_val=ProductAttributeValue(product=m) 
     attr_val.value=self.clean_data['myval'] 
     m.productattributevalue_set.add(attr_val) 

     if commit: 
      m.save() 

     # also doing m2m_save if exists 

     return m 

所以我期待这个失败的product_id =无错误。我也尝试了解django的InlineForm(在管理端)是如何工作的,但似乎他们首先保存了主产品,然后保存了ProductAttributeValue,并且如果说ProductAttributeValue保存失败了,那么他们很好。 对于我的情况,这是不可接受的,即我应该保存所有表格(产品和价值)或失败。我可以肯定地从一开始就用commit = True保存,但正如我所说的,我不希望产品被保存并且不值的情况。

任何帮助表示赞赏。

+0

当然,你不能一个未保存的实例添加到另一个未保存的实例。调用'save()'然后赋值属性有什么问题?你是否期望它以某种方式失败?如果你这样做,那么下面有关于交易的答案。我只是好奇你为什么在这里期待失败..你应该事先做验证,以确保它不会在数据库级别失败。 – 2012-02-03 03:05:15

回答

1

请参阅:https://docs.djangoproject.com/en/dev/topics/db/transactions/ 我认为你可以使用手动事务来做到这一点。提交第一次保存,然后回滚,如果第二个失败:

@transaction.commit_manually 
def viewfunc(request): 
    ... 
    # You can commit/rollback however and whenever you want 
    transaction.commit() 
    ... 

    # But you've got to remember to do it yourself! 
    try: 
     ... 
    except: 
     transaction.rollback() 
    else: 
     transaction.commit() 
+0

感谢您的回答!我很好奇看看是否有其他解决方案。我已经在几个地方使用了transaction.commit_on_success。我想它可以避免手动回滚/提交调用。 – user1039384 2012-02-03 03:32:44

0

由于在保存产品之前没有为您的产品生成标识,因此我认为您不能在产品之前保存属性。无论如何,必须先保存其中的一个 - 最好先保存产品,然后保存属性,并添加一些逻辑来删除产品,如果保存ProductAttributeValues由于某种原因失败。尽管如此,我不明白为什么保存会在ProductAttributeValues上失败,因为验证应该已经在干净的情况下完成了。