3

I have a complex block of code that handle the creation/update of ORM object relationships.

Let's say the models are A and B and the association is a OneToOne A - B (A.b_line points to B).

1) Before creating/updating the associations some A objects needs to be updated and saved into db. During this operation some internal fields of A objects are computed and saved.

2) The updated A object are reloaded from db (because we need the derived computed filed) and the associations with the B objects can proceed.

Example:

def update_and_associate(a_items):
    with transaction.atomic():
        for item in a_items:
            item.field_alpha = 1
            # updates item.field_beta depending on 
            # item.field_alpha 
            item.update_beta()
            item.save()  # Save to db

        with transaction.atomic:
            for item in a_items:
                item.refresh_from_db()
                b = item.b_line
                b.total = a.field_beta
                b.save()

# later...
try:
    update_and_associate(items)
except Exception as e:
    handle_exception(e)

I'm enclosing the code in nested atomic transaction block so that if any exception happen the changes should be rolled back (MySql with InnoDB).

The problem is that in the second atomic block when I reload item with refresh_from_db they are not in sync, meaning they have old values as if the first transaction block didn't run at all.

I though that any changes would be committed as soon as possible but we still had the possibility to roll back in case of exception.

So my question is: by enclosing code in transaction.atomic means that all the write modifications to be performed to the db are postponed until we exit the block? That would explain why refreshed items from db have old values.

Leonardo
  • 4,046
  • 5
  • 44
  • 85
  • 2
    No, enclosing the code in `transaction.atomic` does not postpone write modifications. You are inside the same transaction when you do `refresh_from_db()` so you should get the updated `item`. Perhaps you have cached properties, or you need to refresh `b` as well. See the notes in the [`refresh_from_db`](https://docs.djangoproject.com/en/2.0/ref/models/instances/#django.db.models.Model.refresh_from_db). If you're still stuck, try to create a reproducible example that shows the problem. – Alasdair Feb 21 '18 at 11:36
  • You are right, I found the bug on my side, Should I just delete the question or it might be somehow useful? – Leonardo Feb 21 '18 at 11:42
  • 1
    Glad you found the problem. It's up to you whether or not you keep the question. The code doesn't really demonstrate the problem, so I'm not sure how helpful it will be to future readers. – Alasdair Feb 21 '18 at 11:52

0 Answers0