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:
parent
1ec1633cb2
commit
d389125606
|
@ -61,11 +61,18 @@ class SpatiaLiteIntrospection(DatabaseIntrospection):
|
||||||
|
|
||||||
return field_type, field_params
|
return field_type, field_params
|
||||||
|
|
||||||
def get_indexes(self, cursor, table_name):
|
def get_constraints(self, cursor, table_name):
|
||||||
indexes = super(SpatiaLiteIntrospection, self).get_indexes(cursor, table_name)
|
constraints = super(SpatiaLiteIntrospection, self).get_constraints(cursor, table_name)
|
||||||
cursor.execute('SELECT f_geometry_column '
|
cursor.execute('SELECT f_geometry_column '
|
||||||
'FROM geometry_columns '
|
'FROM geometry_columns '
|
||||||
'WHERE f_table_name=%s AND spatial_index_enabled=1', (table_name,))
|
'WHERE f_table_name=%s AND spatial_index_enabled=1', (table_name,))
|
||||||
for row in cursor.fetchall():
|
for row in cursor.fetchall():
|
||||||
indexes[row[0]] = {'primary_key': False, 'unique': False}
|
constraints['%s__spatial__index' % row[0]] = {
|
||||||
return indexes
|
"columns": [row[0]],
|
||||||
|
"primary_key": False,
|
||||||
|
"unique": False,
|
||||||
|
"foreign_key": None,
|
||||||
|
"check": False,
|
||||||
|
"index": True,
|
||||||
|
}
|
||||||
|
return constraints
|
||||||
|
|
|
@ -70,14 +70,15 @@ class Command(BaseCommand):
|
||||||
relations = connection.introspection.get_relations(cursor, table_name)
|
relations = connection.introspection.get_relations(cursor, table_name)
|
||||||
except NotImplementedError:
|
except NotImplementedError:
|
||||||
relations = {}
|
relations = {}
|
||||||
try:
|
|
||||||
indexes = connection.introspection.get_indexes(cursor, table_name)
|
|
||||||
except NotImplementedError:
|
|
||||||
indexes = {}
|
|
||||||
try:
|
try:
|
||||||
constraints = connection.introspection.get_constraints(cursor, table_name)
|
constraints = connection.introspection.get_constraints(cursor, table_name)
|
||||||
except NotImplementedError:
|
except NotImplementedError:
|
||||||
constraints = {}
|
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)
|
table_description = connection.introspection.get_table_description(cursor, table_name)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
yield "# Unable to inspect table '%s'" % table_name
|
yield "# Unable to inspect table '%s'" % table_name
|
||||||
|
@ -105,11 +106,10 @@ class Command(BaseCommand):
|
||||||
column_to_field_name[column_name] = att_name
|
column_to_field_name[column_name] = att_name
|
||||||
|
|
||||||
# Add primary_key and unique, if necessary.
|
# Add primary_key and unique, if necessary.
|
||||||
if column_name in indexes:
|
if column_name == primary_key_column:
|
||||||
if indexes[column_name]['primary_key']:
|
extra_params['primary_key'] = True
|
||||||
extra_params['primary_key'] = True
|
elif column_name in unique_columns:
|
||||||
elif indexes[column_name]['unique']:
|
extra_params['unique'] = True
|
||||||
extra_params['unique'] = True
|
|
||||||
|
|
||||||
if is_relation:
|
if is_relation:
|
||||||
rel_to = (
|
rel_to = (
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
from django.utils import six
|
|
||||||
|
|
||||||
# Structure returned by DatabaseIntrospection.get_table_list()
|
# Structure returned by DatabaseIntrospection.get_table_list()
|
||||||
TableInfo = namedtuple('TableInfo', ['name', 'type'])
|
TableInfo = namedtuple('TableInfo', ['name', 'type'])
|
||||||
|
|
||||||
|
@ -143,13 +141,14 @@ class BaseDatabaseIntrospection(object):
|
||||||
"""
|
"""
|
||||||
Returns the name of the primary key column for the given table.
|
Returns the name of the primary key column for the given table.
|
||||||
"""
|
"""
|
||||||
for column in six.iteritems(self.get_indexes(cursor, table_name)):
|
for constraint in self.get_constraints(cursor, table_name).values():
|
||||||
if column[1]['primary_key']:
|
if constraint['primary_key']:
|
||||||
return column[0]
|
return constraint['columns'][0]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_indexes(self, cursor, table_name):
|
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
|
Returns a dictionary of indexed fieldname -> infodict for the given
|
||||||
table, where each infodict is in the format:
|
table, where each infodict is in the format:
|
||||||
{'primary_key': boolean representing whether it's the primary key,
|
{'primary_key': boolean representing whether it's the primary key,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import warnings
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
from MySQLdb.constants import FIELD_TYPE
|
from MySQLdb.constants import FIELD_TYPE
|
||||||
|
@ -6,6 +7,7 @@ from django.db.backends.base.introspection import (
|
||||||
BaseDatabaseIntrospection, FieldInfo, TableInfo,
|
BaseDatabaseIntrospection, FieldInfo, TableInfo,
|
||||||
)
|
)
|
||||||
from django.utils.datastructures import OrderedSet
|
from django.utils.datastructures import OrderedSet
|
||||||
|
from django.utils.deprecation import RemovedInDjango21Warning
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
|
|
||||||
FieldInfo = namedtuple('FieldInfo', FieldInfo._fields + ('extra', 'default'))
|
FieldInfo = namedtuple('FieldInfo', FieldInfo._fields + ('extra', 'default'))
|
||||||
|
@ -122,6 +124,10 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
|
||||||
return key_columns
|
return key_columns
|
||||||
|
|
||||||
def get_indexes(self, cursor, table_name):
|
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))
|
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
|
# Do a two-pass search for indexes: on first pass check which indexes
|
||||||
# are multicolumn, on second pass check which single-column indexes
|
# are multicolumn, on second pass check which single-column indexes
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
|
import warnings
|
||||||
|
|
||||||
import cx_Oracle
|
import cx_Oracle
|
||||||
|
|
||||||
from django.db.backends.base.introspection import (
|
from django.db.backends.base.introspection import (
|
||||||
BaseDatabaseIntrospection, FieldInfo, TableInfo,
|
BaseDatabaseIntrospection, FieldInfo, TableInfo,
|
||||||
)
|
)
|
||||||
|
from django.utils.deprecation import RemovedInDjango21Warning
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
|
|
||||||
|
|
||||||
|
@ -117,6 +120,10 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
|
||||||
for row in cursor.fetchall()]
|
for row in cursor.fetchall()]
|
||||||
|
|
||||||
def get_indexes(self, cursor, table_name):
|
def get_indexes(self, cursor, table_name):
|
||||||
|
warnings.warn(
|
||||||
|
"get_indexes() is deprecated in favor of get_constraints().",
|
||||||
|
RemovedInDjango21Warning, stacklevel=2
|
||||||
|
)
|
||||||
sql = """
|
sql = """
|
||||||
SELECT LOWER(uic1.column_name) AS column_name,
|
SELECT LOWER(uic1.column_name) AS column_name,
|
||||||
CASE user_constraints.constraint_type
|
CASE user_constraints.constraint_type
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import warnings
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
from django.db.backends.base.introspection import (
|
from django.db.backends.base.introspection import (
|
||||||
BaseDatabaseIntrospection, FieldInfo, TableInfo,
|
BaseDatabaseIntrospection, FieldInfo, TableInfo,
|
||||||
)
|
)
|
||||||
|
from django.utils.deprecation import RemovedInDjango21Warning
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
|
|
||||||
FieldInfo = namedtuple('FieldInfo', FieldInfo._fields + ('default',))
|
FieldInfo = namedtuple('FieldInfo', FieldInfo._fields + ('default',))
|
||||||
|
@ -124,6 +126,10 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
|
||||||
return key_columns
|
return key_columns
|
||||||
|
|
||||||
def get_indexes(self, cursor, table_name):
|
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
|
# This query retrieves each index on the given table, including the
|
||||||
# first associated field name
|
# first associated field name
|
||||||
cursor.execute(self._get_indexes_query, [table_name])
|
cursor.execute(self._get_indexes_query, [table_name])
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
import re
|
import re
|
||||||
|
import warnings
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
from django.db.backends.base.introspection import (
|
from django.db.backends.base.introspection import (
|
||||||
BaseDatabaseIntrospection, FieldInfo, TableInfo,
|
BaseDatabaseIntrospection, FieldInfo, TableInfo,
|
||||||
)
|
)
|
||||||
|
from django.utils.deprecation import RemovedInDjango21Warning
|
||||||
|
|
||||||
field_size_re = re.compile(r'^\s*(?:var)?char\s*\(\s*(\d+)\s*\)\s*$')
|
field_size_re = re.compile(r'^\s*(?:var)?char\s*\(\s*(\d+)\s*\)\s*$')
|
||||||
FieldInfo = namedtuple('FieldInfo', FieldInfo._fields + ('default',))
|
FieldInfo = namedtuple('FieldInfo', FieldInfo._fields + ('default',))
|
||||||
|
@ -183,6 +185,10 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
|
||||||
return key_columns
|
return key_columns
|
||||||
|
|
||||||
def get_indexes(self, cursor, table_name):
|
def get_indexes(self, cursor, table_name):
|
||||||
|
warnings.warn(
|
||||||
|
"get_indexes() is deprecated in favor of get_constraints().",
|
||||||
|
RemovedInDjango21Warning, stacklevel=2
|
||||||
|
)
|
||||||
indexes = {}
|
indexes = {}
|
||||||
for info in self._table_info(cursor, table_name):
|
for info in self._table_info(cursor, table_name):
|
||||||
if info['pk'] != 0:
|
if info['pk'] != 0:
|
||||||
|
|
|
@ -36,6 +36,8 @@ details on these changes.
|
||||||
* Silencing of exceptions raised while rendering the ``{% include %}`` template
|
* Silencing of exceptions raised while rendering the ``{% include %}`` template
|
||||||
tag will be removed.
|
tag will be removed.
|
||||||
|
|
||||||
|
* ``DatabaseIntrospection.get_indexes()`` will be removed.
|
||||||
|
|
||||||
.. _deprecation-removed-in-2.0:
|
.. _deprecation-removed-in-2.0:
|
||||||
|
|
||||||
2.0
|
2.0
|
||||||
|
|
|
@ -399,6 +399,10 @@ Database backend API
|
||||||
dictionaries with a list of ``'ASC'`` and/or ``'DESC'`` values corresponding
|
dictionaries with a list of ``'ASC'`` and/or ``'DESC'`` values corresponding
|
||||||
to the the ordering of each column in the index.
|
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
|
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
|
:ttag:`{% include %} <include>` template tag is deprecated as the behavior is
|
||||||
often more confusing than helpful. In Django 2.1, the exception will be
|
often more confusing than helpful. In Django 2.1, the exception will be
|
||||||
raised.
|
raised.
|
||||||
|
|
||||||
|
* ``DatabaseIntrospection.get_indexes()`` is deprecated in favor of
|
||||||
|
``DatabaseIntrospection.get_constraints()``.
|
||||||
|
|
|
@ -69,8 +69,8 @@ class OperationTests(TransactionTestCase):
|
||||||
|
|
||||||
def assertSpatialIndexExists(self, table, column):
|
def assertSpatialIndexExists(self, table, column):
|
||||||
with connection.cursor() as cursor:
|
with connection.cursor() as cursor:
|
||||||
indexes = connection.introspection.get_indexes(cursor, table)
|
constraints = connection.introspection.get_constraints(cursor, table)
|
||||||
self.assertIn(column, indexes)
|
self.assertIn([column], [c['columns'] for c in constraints.values()])
|
||||||
|
|
||||||
def alter_gis_model(self, migration_class, model_name, field_name,
|
def alter_gis_model(self, migration_class, model_name, field_name,
|
||||||
blank=False, field_class=None):
|
blank=False, field_class=None):
|
||||||
|
|
|
@ -5,6 +5,8 @@ from unittest import skipUnless
|
||||||
from django.db import connection
|
from django.db import connection
|
||||||
from django.db.utils import DatabaseError
|
from django.db.utils import DatabaseError
|
||||||
from django.test import TransactionTestCase, mock, skipUnlessDBFeature
|
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
|
from .models import Article, ArticleReporter, City, District, Reporter
|
||||||
|
|
||||||
|
@ -169,11 +171,13 @@ class IntrospectionTests(TransactionTestCase):
|
||||||
self.assertEqual(primary_key_column, 'id')
|
self.assertEqual(primary_key_column, 'id')
|
||||||
self.assertEqual(pk_fk_column, 'city_id')
|
self.assertEqual(pk_fk_column, 'city_id')
|
||||||
|
|
||||||
|
@ignore_warnings(category=RemovedInDjango21Warning)
|
||||||
def test_get_indexes(self):
|
def test_get_indexes(self):
|
||||||
with connection.cursor() as cursor:
|
with connection.cursor() as cursor:
|
||||||
indexes = connection.introspection.get_indexes(cursor, Article._meta.db_table)
|
indexes = connection.introspection.get_indexes(cursor, Article._meta.db_table)
|
||||||
self.assertEqual(indexes['reporter_id'], {'unique': False, 'primary_key': False})
|
self.assertEqual(indexes['reporter_id'], {'unique': False, 'primary_key': False})
|
||||||
|
|
||||||
|
@ignore_warnings(category=RemovedInDjango21Warning)
|
||||||
def test_get_indexes_multicol(self):
|
def test_get_indexes_multicol(self):
|
||||||
"""
|
"""
|
||||||
Test that multicolumn indexes are not included in the introspection
|
Test that multicolumn indexes are not included in the introspection
|
||||||
|
|
|
@ -483,9 +483,13 @@ class TestMigrations(TransactionTestCase):
|
||||||
]
|
]
|
||||||
# Only the CharField should have a LIKE index.
|
# Only the CharField should have a LIKE index.
|
||||||
self.assertEqual(like_constraint_columns_list, [['char2']])
|
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.
|
# 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('char', indexes)
|
||||||
self.assertIn('char2', indexes)
|
self.assertIn('char2', indexes)
|
||||||
self.assertIn('text', indexes)
|
self.assertIn('text', indexes)
|
||||||
|
|
|
@ -105,12 +105,20 @@ class SchemaTests(TransactionTestCase):
|
||||||
raise DatabaseError("Table does not exist (empty pragma)")
|
raise DatabaseError("Table does not exist (empty pragma)")
|
||||||
return columns
|
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):
|
def get_indexes(self, table):
|
||||||
"""
|
"""
|
||||||
Get the indexes on the table using a new cursor.
|
Get the indexes on the table using a new cursor.
|
||||||
"""
|
"""
|
||||||
with connection.cursor() as 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):
|
def get_constraints(self, table):
|
||||||
"""
|
"""
|
||||||
|
@ -1685,9 +1693,7 @@ class SchemaTests(TransactionTestCase):
|
||||||
with connection.schema_editor() as editor:
|
with connection.schema_editor() as editor:
|
||||||
editor.create_model(Tag)
|
editor.create_model(Tag)
|
||||||
# Ensure the table is there and has the right PK
|
# Ensure the table is there and has the right PK
|
||||||
self.assertTrue(
|
self.assertEqual(self.get_primary_key(Tag._meta.db_table), 'id')
|
||||||
self.get_indexes(Tag._meta.db_table)['id']['primary_key'],
|
|
||||||
)
|
|
||||||
# Alter to change the PK
|
# Alter to change the PK
|
||||||
id_field = Tag._meta.get_field("id")
|
id_field = Tag._meta.get_field("id")
|
||||||
old_field = Tag._meta.get_field("slug")
|
old_field = Tag._meta.get_field("slug")
|
||||||
|
@ -1702,9 +1708,7 @@ class SchemaTests(TransactionTestCase):
|
||||||
'id',
|
'id',
|
||||||
self.get_indexes(Tag._meta.db_table),
|
self.get_indexes(Tag._meta.db_table),
|
||||||
)
|
)
|
||||||
self.assertTrue(
|
self.assertEqual(self.get_primary_key(Tag._meta.db_table), 'slug')
|
||||||
self.get_indexes(Tag._meta.db_table)['slug']['primary_key'],
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_context_manager_exit(self):
|
def test_context_manager_exit(self):
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in New Issue