Django rollback transaction in save method

I have the following code snippet that overrides the method of saving the 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 will be: the self.qa vote_down_count attribute is incremented by one, but if any exception occurs in the super (self) save method, transactional rollbacks (this means that self.qa.vote_down_count + = 1 is not executed in the database).

Actual behavior: self.qa.vote_down_count + = 1 is database bound, even if an IntegrityError exception is thrown from super (self) save.

Anyone though?

+4
source share
3 answers

Why not just 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 docs mean it, although they say they do it in your view function, so you might not need @transaction.commit_manually by the save() method, instead putting it in the view.

+4
source

Try using savepoints . Something like that:

 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) 
+3
source

I think Mike De Simon's answer is correct.

As for the database, depending on the version of MySQL you are using (if you are using it), it may be that your database uses the MyISAM mechanism, which does not support transactions.

To verify this, simply run mysql in the shell:

 SELECT TABLE_NAME, ENGINE FROM information_schema.TABLES where TABLE_SCHEMA = 'your_db_name' ; 

You can modify your tables in InnoDB and set default_storage_engine for innodb in your MySQL configuration. (More info here: http://parasjain.net/2010/06/08/how-to-switch-to-innodb-database-in-mysql/ .

After that, transactions should work. Better to use Postgres, but if you want to use MySQL / InnoDB, then you probably need a workaround to download shortcuts with direct links (BugFix is ​​already present in Django Trunk, and I also ported it to Django 1.3.1, see Django 1.3 .1.1 on Github ).

0
source

Source: https://habr.com/ru/post/1314663/


All Articles