¿Por qué necesito guardar este modelo antes de agregarlo a otro?
Pregunta
En django, estoy tratando de hacer algo como esto:
# 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 ...
Pero luego me dice:
valor nulo en la columna " product_id " viola la restricción no nula
Pero no entiendo por qué esto es un problema. Cuando se llama a article.save ()
, debe poder crear el producto luego (y generar una identificación).
Puedo solucionar este problema usando este código en el bloque excepto
:
product = Component(name=product_name)
product.save()
article.product = product
Pero la razón por la que esto me preocupa es porque si article.save ()
falla, ya habrá creado un nuevo componente / producto. Quiero que tengan éxito o fracasen juntos.
¿Hay una buena manera de evitar esto?
Solución
Puede solucionar esto usando:
target_product, created_flag = Component.objects.get_or_create(name=product_name)
article.product = target_product
ya que estoy bastante seguro de que get_or_create ()
establecerá la identificación de un objeto, si tiene que crear uno.
Alternativamente, si no le importa tener relaciones FK vacías en la tabla Artículo, puede agregar null = True
a la definición.
Otros consejos
La forma en que funciona Django ManyToManyField es que crea una tabla adicional. Digamos que tienes dos modelos, ModelA y ModelB. Si lo hiciste ...
ModelA.model_b = models.ManyToManyField(ModelB)
Lo que Django realmente hace detrás de escena es crear una tabla ... app_modela_modelb
con tres columnas: id
, model_a_id
, model_b_id
.
Mantenga ese pensamiento en su mente. Con respecto al guardado de ModelB, Django no le asigna una identificación hasta que se guarda. Técnicamente, podría asignarle manualmente una ID y evitar este problema. Parece que está dejando que django maneje lo que es perfectamente aceptable.
Django tiene un problema al hacer el M2M. ¿Por qué? Si ModelB todavía no tiene una identificación, ¿qué pasa en la columna model_b_id
en la tabla M2M? El error para el product_id
nulo es más que probable que sea un error de restricción nula en el campo M2M, no el ID de registro de ModelB.
Si desea que "tengan éxito juntos" o "fallar juntos" Quizás es hora de analizar las transacciones. Usted, por ejemplo, envuelve todo en una transacción y hace una reversión en caso de una falla parcial. No he hecho mucho trabajo personalmente en esta área, así que espero que alguien más sea de ayuda en ese tema.
Hay poco valor al incluir un fragmento de código en las transacciones, ya que debe leer la documentación de Django para obtener una buena comprensión.