Сохранение относительных внешних ключей ModelForm вручную - PullRequest
0 голосов
/ 03 февраля 2012

Ниже приведен упрощенный пример того, чего я пытаюсь достичь:

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 error. Я также попытался понять, как работает InlineForm (на стороне администратора) в django, но, похоже, они сначала сохраняют основной продукт, а затем ProductAttributeValue, и, если, скажем, сохранение ProductAttributeValue не удается, все в порядке. Для моего случая это неприемлемо, то есть я должен сохранить всю форму (как продукт, так и стоимость) или потерпеть неудачу. Конечно, я могу сохранить с помощью commit = True с самого начала, но, как я уже сказал, я не хочу, чтобы продукт сохранялся, а значение не было.

Любая помощь приветствуется.

Ответы [ 2 ]

1 голос
/ 03 февраля 2012

См .: 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 голосов
/ 03 февраля 2012

Поскольку для вашего Продукта не создается идентификатор до его сохранения, я не думаю, что вы сможете сохранить атрибуты до продукта. В любом случае, один должен быть сохранен раньше других - он может сначала сохранить Продукт, затем сохранить атрибуты и добавить некоторую логику для удаления Продукта, если сохранение ProductAttributeValues ​​по какой-то причине не удается. Я не понимаю, почему в ProductAttributeValues ​​все равно произошел сбой сохранения, так как проверка уже должна была быть выполнена в чистом виде.

...