Below is simplified example of what I am trying to achieve:
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
So as I was expecting this fails with product_id=None error. I also tried to understand how django’s InlineForm (on admin side) work, but seems they are saving the main Product first and then the ProductAttributeValue, and if say ProductAttributeValue saving fails they are fine.
For my case it’s not acceptable, i.e. either I should save all the form (both product and the value) or fail. I can certainly save with commit=True from the beginning but as I said, I don’t want a case where product is saved and value not.
Any help appreciated.
See: https://docs.djangoproject.com/en/dev/topics/db/transactions/
I think you can do this using a manual transaction. Commit the first save and then rollback if the second fails: