Skip to content

Commit a067e17

Browse files
committed
BUG25965922: Add support for Django 1.11
This patch fixes the following issues with Django 1.11: - Added optional name parameter to create_cursor in base.py to allow for name variable being passed in base backend _cursor method. - Added DatabaseWrapper class attributes to base.py required in Django 1.11 base backend. - Added column default in DatabaseIntrospection. Tests were modified for regression.
1 parent ed4bfcc commit a067e17

File tree

3 files changed

+83
-13
lines changed

3 files changed

+83
-13
lines changed

lib/mysql/connector/django/base.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@
2222
import warnings
2323

2424
import django
25+
from django.core.exceptions import ImproperlyConfigured
2526
from django.utils.functional import cached_property
2627

2728
try:
2829
import mysql.connector
2930
from mysql.connector.conversion import MySQLConverter, MySQLConverterBase
3031
from mysql.connector.catch23 import PY2
3132
except ImportError as err:
32-
from django.core.exceptions import ImproperlyConfigured
3333
raise ImproperlyConfigured(
3434
"Error loading mysql.connector module: {0}".format(err))
3535

@@ -47,7 +47,6 @@
4747
HAVE_CEXT = True
4848

4949
if version < (1, 1):
50-
from django.core.exceptions import ImproperlyConfigured
5150
raise ImproperlyConfigured(
5251
"MySQL Connector/Python v1.1.0 or newer "
5352
"is required; you have %s" % mysql.connector.__version__)
@@ -332,6 +331,14 @@ def data_types(self):
332331
SchemaEditorClass = DatabaseSchemaEditor
333332
Database = mysql.connector
334333

334+
if django.VERSION >= (1, 11):
335+
client_class = DatabaseClient
336+
creation_class = DatabaseCreation
337+
features_class = DatabaseFeatures
338+
introspection_class = DatabaseIntrospection
339+
ops_class = DatabaseOperations
340+
validation_class = DatabaseValidation
341+
335342
def __init__(self, *args, **kwargs):
336343
super(DatabaseWrapper, self).__init__(*args, **kwargs)
337344

@@ -344,12 +351,13 @@ def __init__(self, *args, **kwargs):
344351
self.converter = DjangoCMySQLConverter()
345352
else:
346353
self.converter = DjangoMySQLConverter()
347-
self.ops = DatabaseOperations(self)
348-
self.features = DatabaseFeatures(self)
349-
self.client = DatabaseClient(self)
350-
self.creation = DatabaseCreation(self)
351-
self.introspection = DatabaseIntrospection(self)
352-
self.validation = DatabaseValidation(self)
354+
if django.VERSION < (1, 11):
355+
self.ops = DatabaseOperations(self)
356+
self.features = DatabaseFeatures(self)
357+
self.client = DatabaseClient(self)
358+
self.creation = DatabaseCreation(self)
359+
self.introspection = DatabaseIntrospection(self)
360+
self.validation = DatabaseValidation(self)
353361

354362
def _valid_connection(self):
355363
if self.connection:
@@ -418,7 +426,7 @@ def init_connection_state(self):
418426
except AttributeError:
419427
self._set_autocommit(self.settings_dict['AUTOCOMMIT'])
420428

421-
def create_cursor(self):
429+
def create_cursor(self, name=None):
422430
# Django 1.6
423431
cursor = self.connection.cursor()
424432
return CursorWrapper(cursor)

lib/mysql/connector/django/introspection.py

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,53 @@ def get_table_list(self, cursor):
7272
else:
7373
return [row[0] for row in cursor.fetchall()]
7474

75-
if django.VERSION >= (1, 8):
75+
if django.VERSION >= (1, 11):
76+
def get_table_description(self, cursor, table_name):
77+
"""
78+
Returns a description of the table, with the DB-API
79+
cursor.description interface."
80+
"""
81+
# - information_schema database gives more accurate results for
82+
# some figures:
83+
# - varchar length returned by cursor.description is an internal
84+
# length, not visible length (#5725)
85+
# - precision and scale (for decimal fields) (#5014)
86+
# - auto_increment is not available in cursor.description
87+
88+
InfoLine = namedtuple('InfoLine', 'col_name data_type max_len '
89+
'num_prec num_scale extra column_default')
90+
cursor.execute("""
91+
SELECT column_name, data_type, character_maximum_length,
92+
numeric_precision, numeric_scale, extra, column_default
93+
FROM information_schema.columns
94+
WHERE table_name = %s AND table_schema = DATABASE()""",
95+
[table_name])
96+
field_info = dict(
97+
(line[0], InfoLine(*line)) for line in cursor.fetchall()
98+
)
99+
100+
cursor.execute("SELECT * FROM %s LIMIT 1"
101+
% self.connection.ops.quote_name(table_name))
102+
to_int = lambda i: int(i) if i is not None else i
103+
fields = []
104+
for line in cursor.description:
105+
col_name = force_text(line[0])
106+
fields.append(
107+
FieldInfo(*(
108+
(col_name,) +
109+
line[1:3] +
110+
(
111+
to_int(field_info[col_name].max_len) or line[3],
112+
to_int(field_info[col_name].num_prec) or line[4],
113+
to_int(field_info[col_name].num_scale) or line[5],
114+
line[6],
115+
field_info[col_name].column_default,
116+
field_info[col_name].extra,
117+
)
118+
))
119+
)
120+
return fields
121+
elif django.VERSION >= (1, 8):
76122
def get_table_description(self, cursor, table_name):
77123
"""
78124
Returns a description of the table, with the DB-API

tests/test_django.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,12 @@ def test_get_table_list(self):
148148
if sys.version_info < (2, 7):
149149
self.assertTrue(exp in self.introspect.get_table_list(cur))
150150
else:
151-
res = any(table.name == exp
152-
for table in self.introspect.get_table_list(cur))
151+
if tests.DJANGO_VERSION < (1, 8):
152+
res = any(table == exp
153+
for table in self.introspect.get_table_list(cur))
154+
else:
155+
res = any(table.name == exp
156+
for table in self.introspect.get_table_list(cur))
153157
self.assertTrue(res, "Table {table_name} not in table list"
154158
"".format(table_name=exp))
155159

@@ -174,7 +178,7 @@ def test_get_table_description(self):
174178
internal_size=20, precision=None, scale=None,
175179
null_ok=1)
176180
]
177-
else:
181+
elif tests.DJANGO_VERSION < (1, 11):
178182
exp = [
179183
FieldInfo(name=u'id', type_code=3, display_size=None,
180184
internal_size=None, precision=10, scale=None,
@@ -186,6 +190,18 @@ def test_get_table_description(self):
186190
internal_size=20, precision=None, scale=None,
187191
null_ok=1, extra=u'')
188192
]
193+
else:
194+
exp = [
195+
FieldInfo(name=u'id', type_code=3, display_size=None,
196+
internal_size=None, precision=10, scale=None,
197+
null_ok=0, default=None, extra=u'auto_increment'),
198+
FieldInfo(name=u'c1', type_code=3, display_size=None,
199+
internal_size=None, precision=10, scale=None,
200+
null_ok=1, default=None, extra=u''),
201+
FieldInfo(name=u'c2', type_code=253, display_size=None,
202+
internal_size=20, precision=None, scale=None,
203+
null_ok=1, default=None, extra=u'')
204+
]
189205
res = self.introspect.get_table_description(cur, 'django_t1')
190206
self.assertEqual(exp, res)
191207

0 commit comments

Comments
 (0)