python-2.7mysql-pythondjango-1.5

Batch SQL INSERT in Django App


I am following this example to batch insert records into a table but modifying it to fit my specific example as such

sql='INSERT INTO CypressApp_grammatrix (name, row_num, col_num, gram_amount) VALUES {}'.format(', '.join(['(%s, %s, %s, %s)']*len(gram_matrix)),)
    #print sql

    params=[]
    for gram in gram_matrix:
        col_num=1
        for g in gram:            
            params.extend([(matrix_name, row_num, col_num, g)])
            col_num += 1
        row_num += 1
    print params

    with closing(connection.cursor()) as cursor:
        cursor.execute(sql, params)

However, upon doing so, I receive this error

return cursor._last_executed.decode('utf-8')
File "/usr/local/lib/python2.7/dist-packages/django/db/backends/mysql/base.py", line 150, in __getattr__
return getattr(self.cursor, attr)
AttributeError: 'Cursor' object has no attribute '_last_executed'

I would like to know why I received this error and what I can do to fix it, although I feel the problem could be with this code that works with MySQL that I did not write

def last_executed_query(self, cursor, sql, params):
    # With MySQLdb, cursor objects have an (undocumented) "_last_executed"
    # attribute where the exact query sent to the database is saved.
    # See MySQLdb/cursors.py in the source distribution.
    return cursor._last_executed.decode('utf-8')

Solution

  • So I don't know if I simply have an old copy of MySQLdb or what, but the problem appear to be with cursors.py. The only spot in that file where you can find _last_executed is here

    def _do_query(self, q):
        db = self._get_db()
        self._last_executed = q
        db.query(q)
        self._do_get_result()
        return self.rowcount
    

    However, the __init__ does not set up this variable as an instance attribute. It's missing completely. So I took the liberty of adding it myself and initializing it to some query string. I assumed any would do, so I just added

    class BaseCursor(object):
    
    """A base for Cursor classes. Useful attributes:
    
    description
        A tuple of DB API 7-tuples describing the columns in
        the last executed query; see PEP-249 for details.
    
    description_flags
        Tuple of column flags for last query, one entry per column
        in the result set. Values correspond to those in
        MySQLdb.constants.FLAG. See MySQL documentation (C API)
        for more information. Non-standard extension.
    
    arraysize
        default number of rows fetchmany() will fetch
    
    """
    
    from _mysql_exceptions import MySQLError, Warning, Error, InterfaceError, \
         DatabaseError, DataError, OperationalError, IntegrityError, \
         InternalError, ProgrammingError, NotSupportedError
    
    def __init__(self, connection):
        from weakref import ref    
        ...
        self._last_executed ="SELECT * FROM T"
    
        ...
    

    Now the cursor object does have the attribute _last_executed and when this function

    def last_executed_query(self, cursor, sql, params):
        # With MySQLdb, cursor objects have an (undocumented) "_last_executed"
        # attribute where the exact query sent to the database is saved.
        # See MySQLdb/cursors.py in the source distribution.
        return cursor._last_executed.decode('utf-8')
    

    in base.py is called, the attribute does exist and so this error

    return cursor._last_executed.decode('utf-8')
    File "/usr/local/lib/python2.7/dist-
    packages/django/db/backends/mysql/base.py", line 150, in __getattr__
    return getattr(self.cursor, attr)
    AttributeError: 'Cursor' object has no attribute '_last_executed'     
    

    will not be encountered. At least that is how I believe it works. In any case, it fixed the situation for me.