Reputation: 1954
Consider I have a save method from a util
class in my Library App. In a self-defined utils.py
:
def update_book_count(key):
key_to_update = BookConfig.objects.get(key=key)
"""
returns {'key': 'Chemistry-700', 'count': 15}
"""
key_to_update.count = key_to_update.count + 1
key_to_update.save()
Consider this code in forms.py
:
class AddBookForm(forms.Form):
#some fields
def save(self):
title = self.cleaned_data.get('title')
category = self.cleaned_data.get('category') #Chemistry
try:
with transaction.atomic():
book = Book(title=title, category=category)
book.save(force_insert=True, force_update=False)
update_book_count(category)
#Say just for this case, I find reservations for this title
loan = Loan.objects.filter(
title=title,status="PENDING_BOOK_PURCHASE")
loan.update(status="PENDING_MEMBER_COLLECTION")
except IntegrityError:
print("Atomic Txn Error")
My question is: Does the atomic()
extend to the database transactions in the update_book_count
method? Specifically:
update_book_count
method fails, does the book.save()
transaction get rolled back too?loan.update()
method fails, does the update_book_count
get rolled back too?Upvotes: 0
Views: 435
Reputation: 12080
First, to answer your questions:
If the exception bubbles up and out of the with
statement (which looking at your code it will), then yes, the the transaction will get rolled back.
Yes, when a transaction is rolled back, everything that has happened so far will be undone.
By the way, you should use signals for automatically updating such count fields so you never have to worry about forgetting to call the method manually (and as before, this will be covered by the transaction if run inside one). And you get the added benefit of it working when objects are deleted.
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
from django.db import transaction
@receiver(post_save, sender=Book)
@receiver(post_delete, sender=Book)
@transaction.atomic
def _update_count(sender, instance, using, **kwargs):
# get total number of books with this category
count = Book.objects.filter(category=instance.category).count()
# update the denormalized data
BookConfig.objects.filter(key=instance.category).update(count=count)
Upvotes: 1