summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacek Bzdak <jbzdak@gmail.com>2015-11-06 17:29:23 +0100
committerTim Graham <timograham@gmail.com>2015-11-25 13:07:00 -0500
commit2cb50f935aa70e91dd6c2f253becd636a2eb6fb7 (patch)
tree24f8855dadd556defaf26c04eb00afbcc9fcd992
parentec202eff84dc56b408f43187e357077521641362 (diff)
Fixed #25274 --- Made inspectdb handle renamed fields in unique_together.
-rw-r--r--django/core/management/commands/inspectdb.py8
-rw-r--r--docs/releases/1.8.8.txt3
-rw-r--r--tests/inspectdb/models.py9
-rw-r--r--tests/inspectdb/tests.py16
4 files changed, 27 insertions, 9 deletions
diff --git a/django/core/management/commands/inspectdb.py b/django/core/management/commands/inspectdb.py
index 9b9e350f4b..7f55f5d022 100644
--- a/django/core/management/commands/inspectdb.py
+++ b/django/core/management/commands/inspectdb.py
@@ -71,6 +71,7 @@ class Command(BaseCommand):
except NotImplementedError:
constraints = {}
used_column_names = [] # Holds column names used in the table so far
+ column_to_field_name = {} # Maps column names to names of model fields
for row in connection.introspection.get_table_description(cursor, table_name):
comment_notes = [] # Holds Field notes, to be displayed in a Python comment.
extra_params = OrderedDict() # Holds Field parameters such as 'db_column'.
@@ -83,6 +84,7 @@ class Command(BaseCommand):
comment_notes.extend(notes)
used_column_names.append(att_name)
+ column_to_field_name[column_name] = att_name
# Add primary_key and unique, if necessary.
if column_name in indexes:
@@ -145,7 +147,7 @@ class Command(BaseCommand):
if comment_notes:
field_desc += ' # ' + ' '.join(comment_notes)
yield ' %s' % field_desc
- for meta_line in self.get_meta(table_name, constraints):
+ for meta_line in self.get_meta(table_name, constraints, column_to_field_name):
yield meta_line
def normalize_col_name(self, col_name, used_column_names, is_relation):
@@ -242,7 +244,7 @@ class Command(BaseCommand):
return field_type, field_params, field_notes
- def get_meta(self, table_name, constraints):
+ def get_meta(self, table_name, constraints, column_to_field_name):
"""
Return a sequence comprising the lines of code necessary
to construct the inner Meta class for the model corresponding
@@ -255,7 +257,7 @@ class Command(BaseCommand):
if len(columns) > 1:
# we do not want to include the u"" or u'' prefix
# so we build the string rather than interpolate the tuple
- tup = '(' + ', '.join("'%s'" % c for c in columns) + ')'
+ tup = '(' + ', '.join("'%s'" % column_to_field_name[c] for c in columns) + ')'
unique_together.append(tup)
meta = ["",
" class Meta:",
diff --git a/docs/releases/1.8.8.txt b/docs/releases/1.8.8.txt
index a24efc00aa..1c4b659782 100644
--- a/docs/releases/1.8.8.txt
+++ b/docs/releases/1.8.8.txt
@@ -9,4 +9,5 @@ Django 1.8.8 fixes several bugs in 1.8.7.
Bugfixes
========
-* ...
+* Fixed incorrect ``unique_together`` field name generation by ``inspectdb``
+ (:ticket:`25274`).
diff --git a/tests/inspectdb/models.py b/tests/inspectdb/models.py
index f7d365b868..ff2fbd6c09 100644
--- a/tests/inspectdb/models.py
+++ b/tests/inspectdb/models.py
@@ -72,6 +72,13 @@ class ColumnTypes(models.Model):
class UniqueTogether(models.Model):
field1 = models.IntegerField()
field2 = models.CharField(max_length=10)
+ from_field = models.IntegerField(db_column='from')
+ non_unique = models.IntegerField(db_column='non__unique_column')
+ non_unique_0 = models.IntegerField(db_column='non_unique__column')
class Meta:
- unique_together = ('field1', 'field2')
+ unique_together = [
+ ('field1', 'field2'),
+ ('from_field', 'field1'),
+ ('non_unique', 'non_unique_0'),
+ ]
diff --git a/tests/inspectdb/tests.py b/tests/inspectdb/tests.py
index db55d68493..06eb2c82f8 100644
--- a/tests/inspectdb/tests.py
+++ b/tests/inspectdb/tests.py
@@ -234,10 +234,18 @@ class InspectDBTestCase(TestCase):
table_name_filter=lambda tn: tn.startswith('inspectdb_uniquetogether'),
stdout=out)
output = out.getvalue()
- self.assertIn(
- " unique_together = (('field1', 'field2'),)", output,
- msg='inspectdb should generate unique_together.'
- )
+ unique_re = re.compile(r'.*unique_together = \((.+),\).*')
+ unique_together_match = re.findall(unique_re, output)
+ # There should be one unique_together tuple.
+ self.assertEqual(len(unique_together_match), 1)
+ fields = unique_together_match[0]
+ # Fields with db_column = field name.
+ self.assertIn("('field1', 'field2')", fields)
+ # Fields from columns whose names are Python keywords.
+ self.assertIn("('field1', 'field2')", fields)
+ # Fields whose names normalize to the same Python field name and hence
+ # are given an integer suffix.
+ self.assertIn("('non_unique_column', 'non_unique_column_0')", fields)
@skipUnless(connection.vendor == 'sqlite',
"Only patched sqlite's DatabaseIntrospection.data_types_reverse for this test")