Ticket #1483: add-mysql-fkey-inspection.2.diff

File add-mysql-fkey-inspection.2.diff, 3.1 KB (added by mir@…, 9 years ago)

patch, adds foreign key handling to inspectdb for MySQL. Revised: Includes code for MySQL 5.0 information_schema

  • django/db/backends/mysql/introspection.py

    diff --git a/django/db/backends/mysql/introspection.py b/django/db/backends/mysql/introspection.py
    index fb97bc4..65f255b 100644
    a b  
    11from django.db import transaction
    22from django.db.backends.mysql.base import quote_name
    33from MySQLdb.constants import FIELD_TYPE
     4from MySQLdb import OperationalError
     5import re
     6
     7# parses a foreign key constraint from show create table
     8#                                                               fieldname              other_field other_table
     9FKEY_PARSER = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)")
    410
    511def get_table_list(cursor):
    612    "Returns a list of table names in the current database."
    def get_table_description(cursor, table_ 
    1218    cursor.execute("SELECT * FROM %s LIMIT 1" % quote_name(table_name))
    1319    return cursor.description
    1420
     21def _name_to_index(cursor, table_name):
     22    """
     23    Returns a dictionary of { field_name: field_index } for the given table.
     24    Indexes are 0-based.
     25    """
     26    descr = get_table_description(cursor, table_name)
     27    res = { }
     28    i=0
     29    for (name, type_code, display_size, internal_size, precision, scale, null_ok) in descr:
     30        res[name] = i
     31        i += 1
     32    return res
     33
    1534def get_relations(cursor, table_name):
    16     raise NotImplementedError
     35    """
     36    Returns a dictionary of {field_index: (field_index_other_table, other_table)}
     37    representing all relationships to the given table. Indexes are 0-based.
     38    """
     39    my_field_dict = _name_to_index(cursor, table_name)
     40    constraints = [ ]
     41    relations = {}
     42   
     43    try:
     44        # This should work for MySQL 5.0
     45        # Shouldn't we limit the select to table_schema?
     46        cursor.execute(
     47            """select column_name, referenced_table_name, referenced_column_name
     48               from information_schema.key_column_usage
     49               where table_name = %s
     50                 and referenced_table_name is not null
     51                 and referenced_column_name is not null""",
     52            [table_name])
     53        constraints.extend(cursor.fetchall())
     54    except OperationalError:
     55        # Fall back to `show create table`
     56        # go through all constraints (== matches) and save these
     57        cursor.execute("SHOW CREATE TABLE "+ table_name)
     58        for row in cursor.fetchall():
     59            pos = 0
     60            while True:
     61                match = FKEY_PARSER.search(row[1], pos)
     62                if match == None:
     63                    break
     64                pos = match.end()
     65                constraints.append(match.groups())
     66
     67    # handle constraints. (can't do this in the loop above since we need the cursor in both places)
     68    for (my_fieldname, other_table, other_field) in constraints:
     69        other_field_index = _name_to_index(cursor, other_table)[other_field]
     70        my_field_index = my_field_dict[my_fieldname]
     71        relations[my_field_index] = (other_field_index, other_table)
     72    return relations
    1773
    1874def get_indexes(cursor, table_name):
    1975    """
Back to Top