Fixed #27533 -- Fixed inspectdb crash if a unique constraint uses an unsupported type.
This commit is contained in:
parent
a170dac887
commit
9aca67bea8
1
AUTHORS
1
AUTHORS
|
@ -567,6 +567,7 @@ answer newbie questions, and generally made Django that much better:
|
||||||
Michael Placentra II <someone@michaelplacentra2.net>
|
Michael Placentra II <someone@michaelplacentra2.net>
|
||||||
Michael Radziej <mir@noris.de>
|
Michael Radziej <mir@noris.de>
|
||||||
Michael Schwarz <michi.schwarz@gmail.com>
|
Michael Schwarz <michi.schwarz@gmail.com>
|
||||||
|
Michael Sinov <sihaelov@gmail.com>
|
||||||
Michael Thornhill <michael.thornhill@gmail.com>
|
Michael Thornhill <michael.thornhill@gmail.com>
|
||||||
Michal Chruszcz <troll@pld-linux.org>
|
Michal Chruszcz <troll@pld-linux.org>
|
||||||
michal@plovarna.cz
|
michal@plovarna.cz
|
||||||
|
|
|
@ -269,16 +269,24 @@ class Command(BaseCommand):
|
||||||
to the given database table name.
|
to the given database table name.
|
||||||
"""
|
"""
|
||||||
unique_together = []
|
unique_together = []
|
||||||
|
has_unsupported_constraint = False
|
||||||
for params in constraints.values():
|
for params in constraints.values():
|
||||||
if params['unique']:
|
if params['unique']:
|
||||||
columns = params['columns']
|
columns = params['columns']
|
||||||
|
if None in columns:
|
||||||
|
has_unsupported_constraint = True
|
||||||
|
columns = [x for x in columns if x is not None]
|
||||||
if len(columns) > 1:
|
if len(columns) > 1:
|
||||||
unique_together.append(str(tuple(column_to_field_name[c] for c in columns)))
|
unique_together.append(str(tuple(column_to_field_name[c] for c in columns)))
|
||||||
managed_comment = " # Created from a view. Don't remove." if is_view else ""
|
managed_comment = " # Created from a view. Don't remove." if is_view else ""
|
||||||
meta = ["",
|
meta = ['']
|
||||||
" class Meta:",
|
if has_unsupported_constraint:
|
||||||
" managed = False%s" % managed_comment,
|
meta.append(' # A unique constraint could not be introspected.')
|
||||||
" db_table = '%s'" % table_name]
|
meta += [
|
||||||
|
' class Meta:',
|
||||||
|
' managed = False%s' % managed_comment,
|
||||||
|
' db_table = %r' % table_name
|
||||||
|
]
|
||||||
if unique_together:
|
if unique_together:
|
||||||
tup = '(' + ', '.join(unique_together) + ',)'
|
tup = '(' + ', '.join(unique_together) + ',)'
|
||||||
meta += [" unique_together = %s" % tup]
|
meta += [" unique_together = %s" % tup]
|
||||||
|
|
|
@ -17,6 +17,7 @@ class PeopleData(models.Model):
|
||||||
|
|
||||||
class PeopleMoreData(models.Model):
|
class PeopleMoreData(models.Model):
|
||||||
people_unique = models.ForeignKey(People, models.CASCADE, unique=True)
|
people_unique = models.ForeignKey(People, models.CASCADE, unique=True)
|
||||||
|
message = models.ForeignKey(Message, models.CASCADE, blank=True, null=True)
|
||||||
license = models.CharField(max_length=255)
|
license = models.CharField(max_length=255)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@ from django.db import connection
|
||||||
from django.db.backends.base.introspection import TableInfo
|
from django.db.backends.base.introspection import TableInfo
|
||||||
from django.test import TestCase, TransactionTestCase, skipUnlessDBFeature
|
from django.test import TestCase, TransactionTestCase, skipUnlessDBFeature
|
||||||
|
|
||||||
|
from .models import PeopleMoreData
|
||||||
|
|
||||||
|
|
||||||
def inspectdb_tables_only(table_name):
|
def inspectdb_tables_only(table_name):
|
||||||
"""
|
"""
|
||||||
|
@ -21,6 +23,7 @@ def special_table_only(table_name):
|
||||||
|
|
||||||
|
|
||||||
class InspectDBTestCase(TestCase):
|
class InspectDBTestCase(TestCase):
|
||||||
|
unique_re = re.compile(r'.*unique_together = \((.+),\).*')
|
||||||
|
|
||||||
def test_stealth_table_name_filter_option(self):
|
def test_stealth_table_name_filter_option(self):
|
||||||
out = StringIO()
|
out = StringIO()
|
||||||
|
@ -212,8 +215,7 @@ class InspectDBTestCase(TestCase):
|
||||||
call_command('inspectdb', 'inspectdb_uniquetogether', stdout=out)
|
call_command('inspectdb', 'inspectdb_uniquetogether', stdout=out)
|
||||||
output = out.getvalue()
|
output = out.getvalue()
|
||||||
self.assertIn(" unique_together = (('", output)
|
self.assertIn(" unique_together = (('", output)
|
||||||
unique_re = re.compile(r'.*unique_together = \((.+),\).*')
|
unique_together_match = re.findall(self.unique_re, output)
|
||||||
unique_together_match = re.findall(unique_re, output)
|
|
||||||
# There should be one unique_together tuple.
|
# There should be one unique_together tuple.
|
||||||
self.assertEqual(len(unique_together_match), 1)
|
self.assertEqual(len(unique_together_match), 1)
|
||||||
fields = unique_together_match[0]
|
fields = unique_together_match[0]
|
||||||
|
@ -225,6 +227,28 @@ class InspectDBTestCase(TestCase):
|
||||||
# are given an integer suffix.
|
# are given an integer suffix.
|
||||||
self.assertIn("('non_unique_column', 'non_unique_column_0')", fields)
|
self.assertIn("('non_unique_column', 'non_unique_column_0')", fields)
|
||||||
|
|
||||||
|
@skipUnless(connection.vendor == 'postgresql', 'PostgreSQL specific SQL')
|
||||||
|
def test_unsupported_unique_together(self):
|
||||||
|
"""Unsupported index types (COALESCE here) are skipped."""
|
||||||
|
with connection.cursor() as c:
|
||||||
|
c.execute(
|
||||||
|
'CREATE UNIQUE INDEX Findex ON %s '
|
||||||
|
'(id, people_unique_id, COALESCE(message_id, -1))' % PeopleMoreData._meta.db_table
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
out = StringIO()
|
||||||
|
call_command(
|
||||||
|
'inspectdb',
|
||||||
|
table_name_filter=lambda tn: tn.startswith(PeopleMoreData._meta.db_table),
|
||||||
|
stdout=out,
|
||||||
|
)
|
||||||
|
output = out.getvalue()
|
||||||
|
self.assertIn('# A unique constraint could not be introspected.', output)
|
||||||
|
self.assertEqual(re.findall(self.unique_re, output), ["('id', 'people_unique')"])
|
||||||
|
finally:
|
||||||
|
with connection.cursor() as c:
|
||||||
|
c.execute('DROP INDEX Findex')
|
||||||
|
|
||||||
@skipUnless(connection.vendor == 'sqlite',
|
@skipUnless(connection.vendor == 'sqlite',
|
||||||
"Only patched sqlite's DatabaseIntrospection.data_types_reverse for this test")
|
"Only patched sqlite's DatabaseIntrospection.data_types_reverse for this test")
|
||||||
def test_custom_fields(self):
|
def test_custom_fields(self):
|
||||||
|
|
Loading…
Reference in New Issue