Commit 023bf66b authored by Jacek Bzdak's avatar Jacek Bzdak Committed by Tim Graham
Browse files

[1.9.x] Fixed #25274 --- Made inspectdb handle renamed fields in unique_together.

Backport of 2cb50f93 from master
parent e2231075
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -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:",
+2 −1
Original line number Diff line number Diff line
@@ -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`).
+8 −1
Original line number Diff line number Diff line
@@ -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'),
        ]
+12 −4
Original line number Diff line number Diff line
@@ -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")