Skip to content

Commit

Permalink
Fixed #1286 -- Improved 'inspectdb' so that it introspects primary_ke…
Browse files Browse the repository at this point in the history
…y=True and unique=True for MySQL. Thanks, gandalf@owca.info

git-svn-id: http://code.djangoproject.com/svn/django/trunk@2346 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information
adrianholovaty committed Feb 18, 2006
1 parent b461282 commit ac97cf5
Show file tree
Hide file tree
Showing 8 changed files with 51 additions and 13 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Expand Up @@ -51,6 +51,7 @@ answer newbie questions, and generally made Django that much better:
deric@monowerks.com deric@monowerks.com
Jeremy Dunck <http://dunck.us/> Jeremy Dunck <http://dunck.us/>
Clint Ecker Clint Ecker
gandalf@owca.info
Baishampayan Ghose Baishampayan Ghose
Espen Grindhaug <http://grindhaug.org/> Espen Grindhaug <http://grindhaug.org/>
Gustavo Picon Gustavo Picon
Expand Down
1 change: 1 addition & 0 deletions django/core/db/__init__.py
Expand Up @@ -37,6 +37,7 @@
get_table_list = dbmod.get_table_list get_table_list = dbmod.get_table_list
get_table_description = dbmod.get_table_description get_table_description = dbmod.get_table_description
get_relations = dbmod.get_relations get_relations = dbmod.get_relations
get_indexes = dbmod.get_indexes
OPERATOR_MAPPING = dbmod.OPERATOR_MAPPING OPERATOR_MAPPING = dbmod.OPERATOR_MAPPING
DATA_TYPES = dbmod.DATA_TYPES DATA_TYPES = dbmod.DATA_TYPES
DATA_TYPES_REVERSE = dbmod.DATA_TYPES_REVERSE DATA_TYPES_REVERSE = dbmod.DATA_TYPES_REVERSE
3 changes: 3 additions & 0 deletions django/core/db/backends/ado_mssql.py
Expand Up @@ -118,6 +118,9 @@ def get_table_description(cursor, table_name):
def get_relations(cursor, table_name): def get_relations(cursor, table_name):
raise NotImplementedError raise NotImplementedError


def get_indexes(cursor, table_name):
raise NotImplementedError

OPERATOR_MAPPING = { OPERATOR_MAPPING = {
'exact': '= %s', 'exact': '= %s',
'iexact': 'LIKE %s', 'iexact': 'LIKE %s',
Expand Down
8 changes: 8 additions & 0 deletions django/core/db/backends/mysql.py
Expand Up @@ -135,6 +135,14 @@ def get_table_description(cursor, table_name):
def get_relations(cursor, table_name): def get_relations(cursor, table_name):
raise NotImplementedError raise NotImplementedError


def get_indexes(cursor, table_name):
"Returns a dict of indexes for given table"
cursor.execute("SHOW INDEX FROM %s" % DatabaseWrapper().quote_name(table_name))
indexes = {}
for row in cursor.fetchall():
indexes[row[4]] = {'keyname': row[2], 'unique': not bool(row[1])}
return indexes

OPERATOR_MAPPING = { OPERATOR_MAPPING = {
'exact': '= %s', 'exact': '= %s',
'iexact': 'LIKE %s', 'iexact': 'LIKE %s',
Expand Down
3 changes: 3 additions & 0 deletions django/core/db/backends/postgresql.py
Expand Up @@ -126,6 +126,9 @@ def get_relations(cursor, table_name):
continue continue
return relations return relations


def get_indexes(cursor, table_name):
raise NotImplementedError

# Register these custom typecasts, because Django expects dates/times to be # Register these custom typecasts, because Django expects dates/times to be
# in Python's native (standard-library) datetime/time format, whereas psycopg # in Python's native (standard-library) datetime/time format, whereas psycopg
# use mx.DateTime by default. # use mx.DateTime by default.
Expand Down
3 changes: 3 additions & 0 deletions django/core/db/backends/sqlite3.py
Expand Up @@ -134,6 +134,9 @@ def get_table_description(cursor, table_name):
def get_relations(cursor, table_name): def get_relations(cursor, table_name):
raise NotImplementedError raise NotImplementedError


def get_indexes(cursor, table_name):
raise NotImplementedError

# Operators and fields ######################################################## # Operators and fields ########################################################


# SQLite requires LIKE statements to include an ESCAPE clause if the value # SQLite requires LIKE statements to include an ESCAPE clause if the value
Expand Down
34 changes: 26 additions & 8 deletions django/core/management.py
Expand Up @@ -595,23 +595,27 @@ def table2model(table_name):
relations = db.get_relations(cursor, table_name) relations = db.get_relations(cursor, table_name)
except NotImplementedError: except NotImplementedError:
relations = {} relations = {}
try:
indexes = db.get_indexes(cursor, table_name)
except NotImplementedError:
indexes = {}
for i, row in enumerate(db.get_table_description(cursor, table_name)): for i, row in enumerate(db.get_table_description(cursor, table_name)):
column_name = row[0] att_name = row[0]
comment_notes = [] # Holds Field notes, to be displayed in a Python comment. comment_notes = [] # Holds Field notes, to be displayed in a Python comment.
extra_params = {} # Holds Field parameters such as 'db_column'. extra_params = {} # Holds Field parameters such as 'db_column'.


if keyword.iskeyword(column_name): if keyword.iskeyword(att_name):
extra_params['db_column'] = column_name extra_params['db_column'] = att_name
column_name += '_field' att_name += '_field'
comment_notes.append('Field renamed because it was a Python reserved word.') comment_notes.append('Field renamed because it was a Python reserved word.')


if relations.has_key(i): if relations.has_key(i):
rel_to = relations[i][1] == table_name and "'self'" or table2model(relations[i][1]) rel_to = relations[i][1] == table_name and "'self'" or table2model(relations[i][1])
field_type = 'ForeignKey(%s' % rel_to field_type = 'ForeignKey(%s' % rel_to
if column_name.endswith('_id'): if att_name.endswith('_id'):
column_name = column_name[:-3] att_name = att_name[:-3]
else: else:
extra_params['db_column'] = column_name extra_params['db_column'] = att_name
else: else:
try: try:
field_type = db.DATA_TYPES_REVERSE[row[1]] field_type = db.DATA_TYPES_REVERSE[row[1]]
Expand All @@ -625,12 +629,26 @@ def table2model(table_name):
field_type, new_params = field_type field_type, new_params = field_type
extra_params.update(new_params) extra_params.update(new_params)


# Add maxlength for all CharFields.
if field_type == 'CharField' and row[3]: if field_type == 'CharField' and row[3]:
extra_params['maxlength'] = row[3] extra_params['maxlength'] = row[3]


# Add primary_key and unique, if necessary.
column_name = extra_params.get('db_column', att_name)
if column_name in indexes:
if indexes[column_name]['keyname'] == 'PRIMARY':
extra_params['primary_key'] = True
elif indexes[column_name]['unique']:
extra_params['unique'] = True

field_type += '(' field_type += '('


field_desc = '%s = meta.%s' % (column_name, field_type) # Don't output 'id = meta.AutoField(primary_key=True)', because
# that's assumed if it doesn't exist.
if att_name == 'id' and field_type == 'AutoField(' and extra_params == {'primary_key': True}:
continue

field_desc = '%s = meta.%s' % (att_name, field_type)
if extra_params: if extra_params:
if not field_desc.endswith('('): if not field_desc.endswith('('):
field_desc += ', ' field_desc += ', '
Expand Down
11 changes: 6 additions & 5 deletions docs/django-admin.txt
Expand Up @@ -112,12 +112,13 @@ output:


This feature is meant as a shortcut, not as definitive model generation. After This feature is meant as a shortcut, not as definitive model generation. After
you run it, you'll want to look over the generated models yourself to make you run it, you'll want to look over the generated models yourself to make
customizations. In particular, you'll need to do this: customizations. In particular, you'll need to rearrange models' order, so that
models that refer to other models are ordered properly.


* Rearrange models' order, so that models that refer to other models are If you're using Django 0.90 or 0.91, you'll need to add ``primary_key=True`` to
ordered properly. one field in each model. In the Django development version, primary keys are
* Add ``primary_key=True`` to one field in each model. The ``inspectdb`` automatically introspected for MySQL, and Django puts in the
doesn't yet introspect primary keys. ``primary_key=True`` where needed.


``inspectdb`` works with PostgreSQL, MySQL and SQLite. Foreign-key detection ``inspectdb`` works with PostgreSQL, MySQL and SQLite. Foreign-key detection
only works in PostgreSQL. only works in PostgreSQL.
Expand Down

0 comments on commit ac97cf5

Please sign in to comment.