Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django rollback transaction in save method

Tags:

python

django

I have the following piece of code overriding the save method of a model:

@transaction.commit_on_success
def save(self, *args, **kwargs):

    try:
        transaction.commit()
        self.qa.vote_down_count += 1
        self.qa.save()

        super(self.__class__, self).save(*args, **kwargs)

    except:
        transaction.rollback()
        raise
    else:
        transaction.commit()

The expected behavior would be: self.qa attribute vote_down_count is incremented by one, but if any exception occurs in the super(self) save method the transaction rollbacks (that means the self.qa.vote_down_count += 1 is not committed in the database).

The actual behavior is: self.qa.vote_down_count += 1 is committed to database even if an IntegrityError exception raises from super(self) save.

Any thoughs?

like image 627
will.i.am Avatar asked Jul 04 '10 12:07

will.i.am


2 Answers

Why not simply do:

@transaction.commit_manually
def save(self, *args, **kwargs):
    try:
        super(self.__class__, self).save(*args, **kwargs)
        self.qa.vote_down_count += 1
        self.qa.save()
    except:
        transaction.rollback()
        raise
    else:
        transaction.commit()

This is how the docs imply to do it, though they say to do this in your view function, so you might not need the @transaction.commit_manually on the save() method, instead putting it on the view.

like image 70
Mike DeSimone Avatar answered Oct 31 '22 04:10

Mike DeSimone


Try to use savepoints. Something like this:

def save(self, *args, **kwargs):

try:
    sid = transaction.savepoint()
    self.qa.vote_down_count += 1
    self.qa.save()

    super(self.__class__, self).save(*args, **kwargs)

except:
    transaction.rollback(sid)
    raise
else:
    transaction.commit(sid)
like image 32
Aldarund Avatar answered Oct 31 '22 02:10

Aldarund