4

I'm running Django 1.4.11. I overrode the save() method of a Django model in a way similar to the following code:

from django.db import models
from django.db import transaction

class MyModel(models.Model):
    # model definition

    @transaction.commit_manually
    def save(self, *args, **kwargs):
        try:
            super(self.__class__, self).save(*args, **kwargs)
            foo() # do_other_things
        except:
            transaction.rollback()
            raise
        else:
            transaction.commit()

When I run my code, sometimes I read this message in the Apache log:

RemovedInDjango18Warning: commit_manually is deprecated in favor of set_autocommit.

How can I implement the same logic with set_autocommit?

floatingpurr
  • 7,749
  • 9
  • 46
  • 106
  • 1
    It's generally a bad idea to use `self.__class__` in `super()`. See this answer for an explanation: http://stackoverflow.com/a/18208725/2615075 – knbk Jun 08 '15 at 15:31

2 Answers2

13

The same logic would look like this:

from django.db import models
from django.db import transaction

class MyModel(models.Model):
    # model definition

    def save(self, *args, **kwargs):
        transaction.set_autocommit(False)
        try:
            super(MyModel, self).save(*args, **kwargs)
            foo() # do_other_things
        except:
            transaction.rollback()
            raise
        else:
            transaction.commit()
        finally:
            transaction.set_autocommit(True)

However, this would be equivalent to using the atomic() decorator:

from django.db import models
from django.db import transaction

class MyModel(models.Model):
    # model definition

    @transaction.atomic
    def save(self, *args, **kwargs):
        super(MyModel, self).save(*args, **kwargs)
        foo() # do_other_things

This will commit the transaction on a successful __exit__, and roll back in the case of an exception.

knbk
  • 52,111
  • 9
  • 124
  • 122
  • Perfect. So if foo() or anything else inside `save()` method raises an exception, the commit on the DBMS of the super `save()` does not take place. Right? – floatingpurr Jun 08 '15 at 12:00
  • 1
    That's right, unless the exception is caught within the atomic block. – knbk Jun 08 '15 at 12:06
1

For the example you have given you can just use transaction.atomic . If the code succeeds, the entire transaction will be committed. If there's an exception, the changes will be rolled back.

@transaction.atomic
def save(self, *args, **kwargs):
    super(self.__class__, self).save(*args, **kwargs)
    foo() # do_other_things
Alasdair
  • 298,606
  • 55
  • 578
  • 516