app/django/db/backends/sqlite3/introspection.py
changeset 54 03e267d67478
child 323 ff1a9aa48cfd
equal deleted inserted replaced
53:57b4279d8c4e 54:03e267d67478
       
     1 from django.db.backends.sqlite3.base import DatabaseOperations
       
     2 
       
     3 quote_name = DatabaseOperations().quote_name
       
     4 
       
     5 def get_table_list(cursor):
       
     6     "Returns a list of table names in the current database."
       
     7     # Skip the sqlite_sequence system table used for autoincrement key
       
     8     # generation.
       
     9     cursor.execute("""
       
    10         SELECT name FROM sqlite_master
       
    11         WHERE type='table' AND NOT name='sqlite_sequence'
       
    12         ORDER BY name""")
       
    13     return [row[0] for row in cursor.fetchall()]
       
    14 
       
    15 def get_table_description(cursor, table_name):
       
    16     "Returns a description of the table, with the DB-API cursor.description interface."
       
    17     return [(info['name'], info['type'], None, None, None, None,
       
    18              info['null_ok']) for info in _table_info(cursor, table_name)]
       
    19 
       
    20 def get_relations(cursor, table_name):
       
    21     raise NotImplementedError
       
    22 
       
    23 def get_indexes(cursor, table_name):
       
    24     """
       
    25     Returns a dictionary of fieldname -> infodict for the given table,
       
    26     where each infodict is in the format:
       
    27         {'primary_key': boolean representing whether it's the primary key,
       
    28          'unique': boolean representing whether it's a unique index}
       
    29     """
       
    30     indexes = {}
       
    31     for info in _table_info(cursor, table_name):
       
    32         indexes[info['name']] = {'primary_key': info['pk'] != 0,
       
    33                                  'unique': False}
       
    34     cursor.execute('PRAGMA index_list(%s)' % quote_name(table_name))
       
    35     # seq, name, unique
       
    36     for index, unique in [(field[1], field[2]) for field in cursor.fetchall()]:
       
    37         if not unique:
       
    38             continue
       
    39         cursor.execute('PRAGMA index_info(%s)' % quote_name(index))
       
    40         info = cursor.fetchall()
       
    41         # Skip indexes across multiple fields
       
    42         if len(info) != 1:
       
    43             continue
       
    44         name = info[0][2] # seqno, cid, name
       
    45         indexes[name]['unique'] = True
       
    46     return indexes
       
    47 
       
    48 def _table_info(cursor, name):
       
    49     cursor.execute('PRAGMA table_info(%s)' % quote_name(name))
       
    50     # cid, name, type, notnull, dflt_value, pk
       
    51     return [{'name': field[1],
       
    52              'type': field[2],
       
    53              'null_ok': not field[3],
       
    54              'pk': field[5]     # undocumented
       
    55              } for field in cursor.fetchall()]
       
    56 
       
    57 # Maps SQL types to Django Field types. Some of the SQL types have multiple
       
    58 # entries here because SQLite allows for anything and doesn't normalize the
       
    59 # field type; it uses whatever was given.
       
    60 BASE_DATA_TYPES_REVERSE = {
       
    61     'bool': 'BooleanField',
       
    62     'boolean': 'BooleanField',
       
    63     'smallint': 'SmallIntegerField',
       
    64     'smallinteger': 'SmallIntegerField',
       
    65     'int': 'IntegerField',
       
    66     'integer': 'IntegerField',
       
    67     'text': 'TextField',
       
    68     'char': 'CharField',
       
    69     'date': 'DateField',
       
    70     'datetime': 'DateTimeField',
       
    71     'time': 'TimeField',
       
    72 }
       
    73 
       
    74 # This light wrapper "fakes" a dictionary interface, because some SQLite data
       
    75 # types include variables in them -- e.g. "varchar(30)" -- and can't be matched
       
    76 # as a simple dictionary lookup.
       
    77 class FlexibleFieldLookupDict:
       
    78     def __getitem__(self, key):
       
    79         key = key.lower()
       
    80         try:
       
    81             return BASE_DATA_TYPES_REVERSE[key]
       
    82         except KeyError:
       
    83             import re
       
    84             m = re.search(r'^\s*(?:var)?char\s*\(\s*(\d+)\s*\)\s*$', key)
       
    85             if m:
       
    86                 return ('CharField', {'max_length': int(m.group(1))})
       
    87             raise KeyError
       
    88 
       
    89 DATA_TYPES_REVERSE = FlexibleFieldLookupDict()