Commit 11662022 authored by Claude Paroz's avatar Claude Paroz
Browse files

Added AutoField introspection for MySQL

Refs #23748.
parent 327df551
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -173,6 +173,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
    supports_binary_field = six.PY2
    supports_regex_backreferencing = False
    supports_date_lookup_using_string = False
    can_introspect_autofield = True
    can_introspect_binary_field = False
    can_introspect_small_integer_field = True
    supports_timezones = False
+31 −18
Original line number Diff line number Diff line
from collections import namedtuple
import re
from .base import FIELD_TYPE
from django.utils.datastructures import OrderedSet
from django.db.backends import BaseDatabaseIntrospection, FieldInfo, TableInfo
from django.utils.encoding import force_text

FieldInfo = namedtuple('FieldInfo', FieldInfo._fields + ('extra',))

foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)")

@@ -32,6 +34,12 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
        FIELD_TYPE.VAR_STRING: 'CharField',
    }

    def get_field_type(self, data_type, description):
        field_type = super(DatabaseIntrospection, self).get_field_type(data_type, description)
        if field_type == 'IntegerField' and 'auto_increment' in description.extra:
            return 'AutoField'
        return field_type

    def get_table_list(self, cursor):
        """
        Returns a list of table and view names in the current database.
@@ -44,28 +52,33 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
        """
        Returns a description of the table, with the DB-API cursor.description interface."
        """
        # varchar length returned by cursor.description is an internal length,
        # not visible length (#5725), use information_schema database to fix this
        cursor.execute("""
            SELECT column_name, character_maximum_length FROM information_schema.columns
            WHERE table_name = %s AND table_schema = DATABASE()
                AND character_maximum_length IS NOT NULL""", [table_name])
        length_map = dict(cursor.fetchall())

        # Also getting precision and scale from information_schema (see #5014)
        # information_schema database gives more accurate results for some figures:
        # - varchar length returned by cursor.description is an internal length,
        #   not visible length (#5725)
        # - precision and scale (for decimal fields) (#5014)
        # - auto_increment is not available in cursor.description
        InfoLine = namedtuple('InfoLine', 'col_name data_type max_len num_prec num_scale extra')
        cursor.execute("""
            SELECT column_name, numeric_precision, numeric_scale FROM information_schema.columns
            WHERE table_name = %s AND table_schema = DATABASE()
                AND data_type='decimal'""", [table_name])
        numeric_map = dict((line[0], tuple(int(n) for n in line[1:])) for line in cursor.fetchall())
            SELECT column_name, data_type, character_maximum_length, numeric_precision, numeric_scale, extra
            FROM information_schema.columns
            WHERE table_name = %s AND table_schema = DATABASE()""", [table_name])
        field_info = dict((line[0], InfoLine(*line)) for line in cursor.fetchall())

        cursor.execute("SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name))
        return [FieldInfo(*((force_text(line[0]),)
        to_int = lambda i: int(i) if i is not None else i
        fields = []
        for line in cursor.description:
            col_name = force_text(line[0])
            fields.append(
                FieldInfo(*((col_name,)
                            + line[1:3]
                            + (length_map.get(line[0], line[3]),)
                            + numeric_map.get(line[0], line[4:6])
                            + (line[6],)))
            for line in cursor.description]
                            + (to_int(field_info[col_name].max_len) or line[3],
                               to_int(field_info[col_name].num_prec) or line[4],
                               to_int(field_info[col_name].num_scale) or line[5])
                            + (line[6],)
                            + (field_info[col_name].extra,)))
            )
        return fields

    def _name_to_index(self, cursor, table_name):
        """