Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fixed #1286 -- Improved 'inspectdb' so that it introspects primary_ke…

…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...
commit ac97cf54af32a1bf4426e613909f0a9af3e02c94 1 parent b461282
@adrianholovaty adrianholovaty authored
View
1  AUTHORS
@@ -51,6 +51,7 @@ answer newbie questions, and generally made Django that much better:
deric@monowerks.com
Jeremy Dunck <http://dunck.us/>
Clint Ecker
+ gandalf@owca.info
Baishampayan Ghose
Espen Grindhaug <http://grindhaug.org/>
Gustavo Picon
View
1  django/core/db/__init__.py
@@ -37,6 +37,7 @@
get_table_list = dbmod.get_table_list
get_table_description = dbmod.get_table_description
get_relations = dbmod.get_relations
+get_indexes = dbmod.get_indexes
OPERATOR_MAPPING = dbmod.OPERATOR_MAPPING
DATA_TYPES = dbmod.DATA_TYPES
DATA_TYPES_REVERSE = dbmod.DATA_TYPES_REVERSE
View
3  django/core/db/backends/ado_mssql.py
@@ -118,6 +118,9 @@ def get_table_description(cursor, table_name):
def get_relations(cursor, table_name):
raise NotImplementedError
+def get_indexes(cursor, table_name):
+ raise NotImplementedError
+
OPERATOR_MAPPING = {
'exact': '= %s',
'iexact': 'LIKE %s',
View
8 django/core/db/backends/mysql.py
@@ -135,6 +135,14 @@ def get_table_description(cursor, table_name):
def get_relations(cursor, table_name):
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 = {
'exact': '= %s',
'iexact': 'LIKE %s',
View
3  django/core/db/backends/postgresql.py
@@ -126,6 +126,9 @@ def get_relations(cursor, table_name):
continue
return relations
+def get_indexes(cursor, table_name):
+ raise NotImplementedError
+
# Register these custom typecasts, because Django expects dates/times to be
# in Python's native (standard-library) datetime/time format, whereas psycopg
# use mx.DateTime by default.
View
3  django/core/db/backends/sqlite3.py
@@ -134,6 +134,9 @@ def get_table_description(cursor, table_name):
def get_relations(cursor, table_name):
raise NotImplementedError
+def get_indexes(cursor, table_name):
+ raise NotImplementedError
+
# Operators and fields ########################################################
# SQLite requires LIKE statements to include an ESCAPE clause if the value
View
34 django/core/management.py
@@ -595,23 +595,27 @@ def table2model(table_name):
relations = db.get_relations(cursor, table_name)
except NotImplementedError:
relations = {}
+ try:
+ indexes = db.get_indexes(cursor, table_name)
+ except NotImplementedError:
+ indexes = {}
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.
extra_params = {} # Holds Field parameters such as 'db_column'.
- if keyword.iskeyword(column_name):
- extra_params['db_column'] = column_name
- column_name += '_field'
+ if keyword.iskeyword(att_name):
+ extra_params['db_column'] = att_name
+ att_name += '_field'
comment_notes.append('Field renamed because it was a Python reserved word.')
if relations.has_key(i):
rel_to = relations[i][1] == table_name and "'self'" or table2model(relations[i][1])
field_type = 'ForeignKey(%s' % rel_to
- if column_name.endswith('_id'):
- column_name = column_name[:-3]
+ if att_name.endswith('_id'):
+ att_name = att_name[:-3]
else:
- extra_params['db_column'] = column_name
+ extra_params['db_column'] = att_name
else:
try:
field_type = db.DATA_TYPES_REVERSE[row[1]]
@@ -625,12 +629,26 @@ def table2model(table_name):
field_type, new_params = field_type
extra_params.update(new_params)
+ # Add maxlength for all CharFields.
if field_type == 'CharField' and 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_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 not field_desc.endswith('('):
field_desc += ', '
View
11 docs/django-admin.txt
@@ -112,12 +112,13 @@ output:
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
-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
- ordered properly.
- * Add ``primary_key=True`` to one field in each model. The ``inspectdb``
- doesn't yet introspect primary keys.
+If you're using Django 0.90 or 0.91, you'll need to add ``primary_key=True`` to
+one field in each model. In the Django development version, primary keys are
+automatically introspected for MySQL, and Django puts in the
+``primary_key=True`` where needed.
``inspectdb`` works with PostgreSQL, MySQL and SQLite. Foreign-key detection
only works in PostgreSQL.
Please sign in to comment.
Something went wrong with that request. Please try again.