Fixed #27098 -- Deprecated DatabaseIntrospection.get_indexes

Thanks Akshesh <aksheshdoshi@gmail.com> for help with the PostgreSQL query.
Thanks Tim Graham for the review.
This commit is contained in:
Claude Paroz 2016-08-20 12:14:02 +02:00
parent 1ec1633cb2
commit d389125606
13 changed files with 81 additions and 29 deletions

View File

@ -61,11 +61,18 @@ class SpatiaLiteIntrospection(DatabaseIntrospection):
return field_type, field_params
def get_indexes(self, cursor, table_name):
indexes = super(SpatiaLiteIntrospection, self).get_indexes(cursor, table_name)
def get_constraints(self, cursor, table_name):
constraints = super(SpatiaLiteIntrospection, self).get_constraints(cursor, table_name)
cursor.execute('SELECT f_geometry_column '
'FROM geometry_columns '
'WHERE f_table_name=%s AND spatial_index_enabled=1', (table_name,))
for row in cursor.fetchall():
indexes[row[0]] = {'primary_key': False, 'unique': False}
return indexes
constraints['%s__spatial__index' % row[0]] = {
"columns": [row[0]],
"primary_key": False,
"unique": False,
"foreign_key": None,
"check": False,
"index": True,
}
return constraints

View File

@ -70,14 +70,15 @@ class Command(BaseCommand):
relations = connection.introspection.get_relations(cursor, table_name)
except NotImplementedError:
relations = {}
try:
indexes = connection.introspection.get_indexes(cursor, table_name)
except NotImplementedError:
indexes = {}
try:
constraints = connection.introspection.get_constraints(cursor, table_name)
except NotImplementedError:
constraints = {}
primary_key_column = connection.introspection.get_primary_key_column(cursor, table_name)
unique_columns = [
c['columns'][0] for c in constraints.values()
if c['unique'] and len(c['columns']) == 1
]
table_description = connection.introspection.get_table_description(cursor, table_name)
except Exception as e:
yield "# Unable to inspect table '%s'" % table_name
@ -105,11 +106,10 @@ class Command(BaseCommand):
column_to_field_name[column_name] = att_name
# Add primary_key and unique, if necessary.
if column_name in indexes:
if indexes[column_name]['primary_key']:
extra_params['primary_key'] = True
elif indexes[column_name]['unique']:
extra_params['unique'] = True
if column_name == primary_key_column:
extra_params['primary_key'] = True
elif column_name in unique_columns:
extra_params['unique'] = True
if is_relation:
rel_to = (

View File

@ -1,7 +1,5 @@
from collections import namedtuple
from django.utils import six
# Structure returned by DatabaseIntrospection.get_table_list()
TableInfo = namedtuple('TableInfo', ['name', 'type'])
@ -143,13 +141,14 @@ class BaseDatabaseIntrospection(object):
"""
Returns the name of the primary key column for the given table.
"""
for column in six.iteritems(self.get_indexes(cursor, table_name)):
if column[1]['primary_key']:
return column[0]
for constraint in self.get_constraints(cursor, table_name).values():
if constraint['primary_key']:
return constraint['columns'][0]
return None
def get_indexes(self, cursor, table_name):
"""
Deprecated in Django 1.11, use get_constraints instead.
Returns a dictionary of indexed fieldname -> infodict for the given
table, where each infodict is in the format:
{'primary_key': boolean representing whether it's the primary key,

View File

@ -1,3 +1,4 @@
import warnings
from collections import namedtuple
from MySQLdb.constants import FIELD_TYPE
@ -6,6 +7,7 @@ from django.db.backends.base.introspection import (
BaseDatabaseIntrospection, FieldInfo, TableInfo,
)
from django.utils.datastructures import OrderedSet
from django.utils.deprecation import RemovedInDjango21Warning
from django.utils.encoding import force_text
FieldInfo = namedtuple('FieldInfo', FieldInfo._fields + ('extra', 'default'))
@ -122,6 +124,10 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
return key_columns
def get_indexes(self, cursor, table_name):
warnings.warn(
"get_indexes() is deprecated in favor of get_constraints().",
RemovedInDjango21Warning, stacklevel=2
)
cursor.execute("SHOW INDEX FROM %s" % self.connection.ops.quote_name(table_name))
# Do a two-pass search for indexes: on first pass check which indexes
# are multicolumn, on second pass check which single-column indexes

View File

@ -1,8 +1,11 @@
import warnings
import cx_Oracle
from django.db.backends.base.introspection import (
BaseDatabaseIntrospection, FieldInfo, TableInfo,
)
from django.utils.deprecation import RemovedInDjango21Warning
from django.utils.encoding import force_text
@ -117,6 +120,10 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
for row in cursor.fetchall()]
def get_indexes(self, cursor, table_name):
warnings.warn(
"get_indexes() is deprecated in favor of get_constraints().",
RemovedInDjango21Warning, stacklevel=2
)
sql = """
SELECT LOWER(uic1.column_name) AS column_name,
CASE user_constraints.constraint_type

View File

@ -1,10 +1,12 @@
from __future__ import unicode_literals
import warnings
from collections import namedtuple
from django.db.backends.base.introspection import (
BaseDatabaseIntrospection, FieldInfo, TableInfo,
)
from django.utils.deprecation import RemovedInDjango21Warning
from django.utils.encoding import force_text
FieldInfo = namedtuple('FieldInfo', FieldInfo._fields + ('default',))
@ -124,6 +126,10 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
return key_columns
def get_indexes(self, cursor, table_name):
warnings.warn(
"get_indexes() is deprecated in favor of get_constraints().",
RemovedInDjango21Warning, stacklevel=2
)
# This query retrieves each index on the given table, including the
# first associated field name
cursor.execute(self._get_indexes_query, [table_name])

View File

@ -1,9 +1,11 @@
import re
import warnings
from collections import namedtuple
from django.db.backends.base.introspection import (
BaseDatabaseIntrospection, FieldInfo, TableInfo,
)
from django.utils.deprecation import RemovedInDjango21Warning
field_size_re = re.compile(r'^\s*(?:var)?char\s*\(\s*(\d+)\s*\)\s*$')
FieldInfo = namedtuple('FieldInfo', FieldInfo._fields + ('default',))
@ -183,6 +185,10 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
return key_columns
def get_indexes(self, cursor, table_name):
warnings.warn(
"get_indexes() is deprecated in favor of get_constraints().",
RemovedInDjango21Warning, stacklevel=2
)
indexes = {}
for info in self._table_info(cursor, table_name):
if info['pk'] != 0:

View File

@ -36,6 +36,8 @@ details on these changes.
* Silencing of exceptions raised while rendering the ``{% include %}`` template
tag will be removed.
* ``DatabaseIntrospection.get_indexes()`` will be removed.
.. _deprecation-removed-in-2.0:
2.0

View File

@ -399,6 +399,10 @@ Database backend API
dictionaries with a list of ``'ASC'`` and/or ``'DESC'`` values corresponding
to the the ordering of each column in the index.
* :djadmin:`inspectdb` no longer calls ``DatabaseIntrospection.get_indexes()``
which is deprecated. Custom database backends should ensure all types of
indexes are returned by ``DatabaseIntrospection.get_constraints()``.
Dropped support for PostgreSQL 9.2 and PostGIS 2.0
--------------------------------------------------
@ -549,3 +553,6 @@ Miscellaneous
:ttag:`{% include %} <include>` template tag is deprecated as the behavior is
often more confusing than helpful. In Django 2.1, the exception will be
raised.
* ``DatabaseIntrospection.get_indexes()`` is deprecated in favor of
``DatabaseIntrospection.get_constraints()``.

View File

@ -69,8 +69,8 @@ class OperationTests(TransactionTestCase):
def assertSpatialIndexExists(self, table, column):
with connection.cursor() as cursor:
indexes = connection.introspection.get_indexes(cursor, table)
self.assertIn(column, indexes)
constraints = connection.introspection.get_constraints(cursor, table)
self.assertIn([column], [c['columns'] for c in constraints.values()])
def alter_gis_model(self, migration_class, model_name, field_name,
blank=False, field_class=None):

View File

@ -5,6 +5,8 @@ from unittest import skipUnless
from django.db import connection
from django.db.utils import DatabaseError
from django.test import TransactionTestCase, mock, skipUnlessDBFeature
from django.test.utils import ignore_warnings
from django.utils.deprecation import RemovedInDjango21Warning
from .models import Article, ArticleReporter, City, District, Reporter
@ -169,11 +171,13 @@ class IntrospectionTests(TransactionTestCase):
self.assertEqual(primary_key_column, 'id')
self.assertEqual(pk_fk_column, 'city_id')
@ignore_warnings(category=RemovedInDjango21Warning)
def test_get_indexes(self):
with connection.cursor() as cursor:
indexes = connection.introspection.get_indexes(cursor, Article._meta.db_table)
self.assertEqual(indexes['reporter_id'], {'unique': False, 'primary_key': False})
@ignore_warnings(category=RemovedInDjango21Warning)
def test_get_indexes_multicol(self):
"""
Test that multicolumn indexes are not included in the introspection

View File

@ -483,9 +483,13 @@ class TestMigrations(TransactionTestCase):
]
# Only the CharField should have a LIKE index.
self.assertEqual(like_constraint_columns_list, [['char2']])
with connection.cursor() as cursor:
indexes = connection.introspection.get_indexes(cursor, table_name)
# All fields should have regular indexes.
with connection.cursor() as cursor:
indexes = [
c['columns'][0]
for c in connection.introspection.get_constraints(cursor, table_name).values()
if c['index'] and len(c['columns']) == 1
]
self.assertIn('char', indexes)
self.assertIn('char2', indexes)
self.assertIn('text', indexes)

View File

@ -105,12 +105,20 @@ class SchemaTests(TransactionTestCase):
raise DatabaseError("Table does not exist (empty pragma)")
return columns
def get_primary_key(self, table):
with connection.cursor() as cursor:
return connection.introspection.get_primary_key_column(cursor, table)
def get_indexes(self, table):
"""
Get the indexes on the table using a new cursor.
"""
with connection.cursor() as cursor:
return connection.introspection.get_indexes(cursor, table)
return [
c['columns'][0]
for c in connection.introspection.get_constraints(cursor, table).values()
if c['index'] and len(c['columns']) == 1
]
def get_constraints(self, table):
"""
@ -1685,9 +1693,7 @@ class SchemaTests(TransactionTestCase):
with connection.schema_editor() as editor:
editor.create_model(Tag)
# Ensure the table is there and has the right PK
self.assertTrue(
self.get_indexes(Tag._meta.db_table)['id']['primary_key'],
)
self.assertEqual(self.get_primary_key(Tag._meta.db_table), 'id')
# Alter to change the PK
id_field = Tag._meta.get_field("id")
old_field = Tag._meta.get_field("slug")
@ -1702,9 +1708,7 @@ class SchemaTests(TransactionTestCase):
'id',
self.get_indexes(Tag._meta.db_table),
)
self.assertTrue(
self.get_indexes(Tag._meta.db_table)['slug']['primary_key'],
)
self.assertEqual(self.get_primary_key(Tag._meta.db_table), 'slug')
def test_context_manager_exit(self):
"""