Por que eu preciso para salvar este modelo antes de adicionar outro?
Pergunta
No Django, eu estou tentando fazer algo como isto:
# 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 ...
Mas então ele me diz:
valor nulo na coluna "product_id" viola não-nula restrição
Mas eu não entendo por que este é um problema. Quando article.save()
é chamado, ele deve ser capaz a criar o produto então (e gerar um id).
Eu posso contornar esse problema usando este código no bloco except
:
product = Component(name=product_name)
product.save()
article.product = product
Mas a razão pela qual este me preocupa é porque se article.save()
falhar, ele já terá criado um novo componente / produto. Eu quero que eles ter sucesso ou falhar juntos.
Existe uma boa maneira de contornar este problema?
Solução
Você pode contornar isso usando:
target_product, created_flag = Component.objects.get_or_create(name=product_name)
article.product = target_product
como eu tenho certeza que get_or_create()
irá definir o ID de um objeto, se tem que criar um.
Como alternativa, se você não se importa as relações FK vazios na mesa de artigo, você pode adicionar null=True
para a definição.
Outras dicas
A forma como o Django ManyToManyField funciona é que ele cria uma tabela extra. Então, digamos que você tem dois modelos, ModelA e ModelB. Se você fez ...
ModelA.model_b = models.ManyToManyField(ModelB)
O Django realmente faz nos bastidores é que ele cria uma tabela ... app_modela_modelb
com três colunas: id
, model_a_id
, model_b_id
mantenha esse pensamento em sua mente. Em relação à economia de ModelB, Django não atribuir a ela um ID até que seja salva. Você poderia tecnicamente atribuí-lo manualmente um ID e evitar este problema. Parece que você está deixando django pega o que é perfeitamente aceitável.
Django tem um problema, em seguida, fazendo o M2M. Por quê? Se ModelB não tem um ID ainda, o que se passa na coluna model_b_id
na mesa de M2M? O erro para product_id
nulo é mais do que provável um erro nula restrição no campo M2M, não o ModelB ID de registo.
Se você gostaria que eles "ter sucesso juntos" ou "fracassaremos juntos", talvez tempo de olhar para as transações. Você, por exemplo, enrole a coisa toda em uma transação, e fazer uma reversão no caso de uma falha parcial. Eu não fiz um monte de trabalho pessoalmente nesta área por isso espero que alguém vai ser de assistência sobre o assunto.
Há pouco valor em incluindo um trecho de código sobre as transações, como você deve ler a documentação Django para ganhar um bom entendimento.