Зачем мне сохранять эту модель перед добавлением в другую? - PullRequest
0 голосов
/ 27 ноября 2009

В 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(), он должен создать продукт , затем (и сгенерировать идентификатор).

Я могу обойти эту проблему, используя этот код в блоке except:

product = Component(name=product_name)
product.save()
article.product = product

Но причина, по которой меня это беспокоит, в том, что если article.save() не удастся, он уже создаст новый компонент / продукт. Я хочу, чтобы они преуспели или потерпели неудачу вместе.

Есть ли хороший способ обойти это?

Ответы [ 3 ]

4 голосов
/ 27 ноября 2009

Принцип работы Django ManyToManyField заключается в том, что он создает дополнительную таблицу. Скажем, у вас есть две модели, ModelA и ModelB. Если вы сделали ...

ModelA.model_b = models.ManyToManyField(ModelB)

Что Django на самом деле делает за сценой, так это создает таблицу ... app_modela_modelb с тремя столбцами: id, model_a_id, model_b_id.

Держите эту мысль в уме. Что касается сохранения ModelB, Django не присваивает ему идентификатор, пока он не будет сохранен. Технически вы можете вручную назначить ему идентификатор и избежать этой проблемы. Кажется, вы позволяете django справиться с тем, что вполне приемлемо.

У Джанго проблема с M2M. Зачем? Если у ModelB еще нет идентификатора, что входит в столбец model_b_id таблицы M2M? Ошибка для нуля product_id более чем вероятна ошибка ограничения нуля для поля M2M, а не для идентификатора записи ModelB.

Если вы хотите, чтобы они "преуспели вместе" или "провалились вместе", возможно, пришло время заняться транзакциями. Вы, например, заключаете все это в транзакцию и выполняете откат в случае частичного сбоя. Лично я не проделал большую работу лично в этой области, так что, надеюсь, кто-то еще поможет в этой теме.

1 голос
/ 27 ноября 2009

Нет смысла включать фрагмент кода для транзакций, так как вам нужно прочитать документацию Django , чтобы получить хорошее понимание.

1 голос
/ 27 ноября 2009

Вы можете обойти это, используя:

target_product, created_flag = Component.objects.get_or_create(name=product_name)
article.product = target_product

как я уверен, get_or_create() установит id объекта, если он должен его создать.

Кроме того, если вы не возражаете против пустых отношений FK в таблице Article, вы можете добавить null=True к определению.

...