Question

In django, I'm trying to do something like this:

# 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 ...

But then it tells me:

null value in column "product_id" violates not-null constraint

But I don't understand why this is a problem. When article.save() is called, it should be able the create the product then (and generate an id).

I can get around this problem by using this code in the except block:

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

But the reason this concerns me is because if article.save() fails, it will already have created a new component/product. I want them to succeed or fail together.

Is there a nice way to get around this?

Was it helpful?

Solution

You could get around this by using :

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

as I'm pretty sure get_or_create() will set the id of an object, if it has to create one.

Alternatively, if you don't mind empty FK relations on the Article table, you could add null=True to the definition.

OTHER TIPS

The way the Django ManyToManyField works is that it creates an extra table. So say you have two models, ModelA and ModelB. If you did...

ModelA.model_b = models.ManyToManyField(ModelB)

What Django actually does behind the scenes is it creates a table... app_modela_modelb with three columns: id, model_a_id, model_b_id.

Hold that thought in your mind. Regarding the saving of ModelB, Django does not assign it an ID until it's saved. You could technically manually assign it an ID and avoid this problem. It seems you're letting django handle that which is perfectly acceptable.

Django has a problem then doing the M2M. Why? If ModelB doesn't have an id yet, what goes in the model_b_id column on the M2M table? The error for null product_id is more than likely a null constraint error on the M2M field, not the ModelB record id.

If you would like them to "succeed together" or "fail together" perhaps it's time to look into transactions. You, for example, wrap the whole thing in a transaction, and do a rollback in the case of a partial failure. I haven't done a whole lot of work personally in this area so hopefully someone else will be of assistance on that topic.

There's little value in including a code snippet on transactions, as you should read the Django documentation to gain a good understanding.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top