手动保存ModelForm相对外键

时间:2012-02-03 01:44:09

标签: django django-models django-forms foreign-keys

下面是我想要实现的简化示例:

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 = None错误而失败。我也试图理解django的InlineForm(在管理端)如何工作,但似乎他们首先保存主要产品然后保存ProductAttributeValue,如果说ProductAttributeValue保存失败他们就没事了。 对于我的情况,这是不可接受的,即我应该保存所有表格(产品和价值)或失败。我当然可以从一开始就使用commit = True进行保存,但正如我所说的,我不想要一个保存产品并且没有价值的情况。

任何帮助表示感谢。

2 个答案:

答案 0 :(得分: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()

答案 1 :(得分:0)

由于在保存之前没有为您的产品生成ID,因此我认为您无法在产品之前保存属性。无论如何,必须先保存一个 - 不妨保存产品,然后保存属性,并添加一些逻辑来删除产品,如果由于某种原因保存ProductAttributeValues失败。不过,我不知道为什么保存会在ProductAttributeValues上失败,因为验证应该已经在clean中完成了。