Perché devo salvare questo modello prima di aggiungerlo a un altro?
Domanda
In django, sto provando a fare qualcosa del genere:
# 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 ...
Ma poi mi dice:
valore nullo nella colonna " product_id " viola il vincolo non nullo
Ma non capisco perché questo sia un problema. Quando viene chiamato article.save ()
, dovrebbe essere in grado di creare il prodotto quindi (e generare un ID).
Posso aggirare questo problema utilizzando questo codice nel blocco tranne
:
product = Component(name=product_name)
product.save()
article.product = product
Ma la ragione per cui mi preoccupa è perché se article.save ()
fallisce, avrà già creato un nuovo componente / prodotto. Voglio che abbiano successo o falliscano insieme.
C'è un bel modo per aggirare questo?
Soluzione
Puoi aggirare il problema usando:
target_product, created_flag = Component.objects.get_or_create(name=product_name)
article.product = target_product
poiché sono abbastanza sicuro che get_or_create ()
imposterà l'id di un oggetto, se deve crearne uno.
In alternativa, se non ti dispiace relazioni FK vuote nella tabella degli articoli, puoi aggiungere null = True
alla definizione.
Altri suggerimenti
Il modo in cui Django ManyToManyField funziona è che crea una tabella aggiuntiva. Quindi supponiamo di avere due modelli, ModelA e ModelB. Se lo facessi ...
ModelA.model_b = models.ManyToManyField(ModelB)
Quello che Django effettivamente fa dietro le quinte è che crea una tabella ... app_modela_modelb
con tre colonne: id
, model_a_id
, model_b_id
.
Tieni quel pensiero nella tua mente. Per quanto riguarda il salvataggio di ModelB, Django non gli assegna un ID finché non viene salvato. È possibile tecnicamente assegnargli manualmente un ID ed evitare questo problema. Sembra che stai lasciando che Django gestisca ciò che è perfettamente accettabile.
Django ha un problema a fare M2M. Perché? Se ModelB non ha ancora un ID, cosa succede nella colonna model_b_id
sulla tabella M2M? L'errore per null product_id
è molto probabilmente un errore di vincolo null nel campo M2M, non nell'ID record ModelB.
Se desideri che " riescano insieme " o " fallire insieme " forse è tempo di esaminare le transazioni. Ad esempio, si avvolge il tutto in una transazione e si esegue un rollback in caso di errore parziale. Non ho svolto molto lavoro personalmente in questo settore, quindi spero che qualcun altro possa essere di aiuto su questo argomento.
C'è poco valore nell'includere un frammento di codice sulle transazioni, come dovresti leggere la documentazione di Django per acquisire una buona comprensione.