On 8/9/06, Nicolas Lehuen <[EMAIL PROTECTED]> wrote:
I think MySQL has also the support for INSERT OR UPDATE requests which are
quite handy when implementing do_save.

You probably mean the REPLACE statement,
  http://www.mysql.org/doc/refman/5.1/en/replace.html

If you want something a little more like standard SQL like, you can
also use something a little more pythonic which eliminates the need
to do a select statement first,

   try:
       c.execute( "insert into ...." )
   except MySQLdb.IntegrityError, err:
       if e.args[0] == 1062: # duplicate key
           c.execute( "update ....." )
       else:
           raise

Unfortunately the MySQLdb module doesn't seem to provide
any identifiers for the magic constant numbers like 1062.

Also you may want to (should) use transactions, especially for
the methods which execute multiple SQL statements.  This will
help eliminate some of the race conditions that exist in your
code.  Something like the following helper methods can be useful:

   def __init_(self, ...):
       ....
       self.in_trans = False

   def start_transaction(self):
       """Begin a database transaction.

       You must later call either commit_transaction() or
rollback_transaction().
       """
       import datetime
       if self.in_trans:
           raise RuntimeError('Attempted to start a nested transaction')
       self.db.autocommit(False)
       c = self.db.cursor()   # Yes, use a private local cursor here
       c.execute("start transaction")
       self.in_trans = True
       c.close()

   def commit_transaction(self):
       """Commit the current database transaction.

       The transaction should have started with the start_transaction() method.
       """
       if not self.in_trans:
           raise RuntimeError('Attempted to commit before a
transaction was started')
       db.commit()
       self.in_trans = False
       db.autocommit(True)

   def rollback_transaction(self):
       """Roll back the current database transaction.

       The transaction should have started with the start_transaction() method.
       """
       if not self.in_trans:
           raise RuntimeError('Attempted to rollback before a
transaction was started')
       db.rollback()
       self.in_trans = False
       db.autocommit(True)

And then in your methods that use multple SQL statements use
a code pattern like:

   def some_complex_method(self):
       success = False
       self.start_transaction()
       try:
           try:
               cursor.execute(" statement 1 ")
               cursor.execute(" statement 2 ")
               cursor.execute(" statement 3 ")
          except:
               success = False
               raise
          else:
               success = True
       finally:
           if success:
               self.commit_transaction()
           else:
               self.rollback_transaction()
       return

Supposedly in a future version of python you'll be able to
collapse the nested (try: try: except: finally:) into a single
try block.
--
Deron Meranda

Reply via email to