mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	[1.8.x] Fixed #25274 --- Made inspectdb handle renamed fields in unique_together.
Backport of 2cb50f935a from master
			
			
This commit is contained in:
		| @@ -73,6 +73,7 @@ class Command(BaseCommand): | |||||||
|                 except NotImplementedError: |                 except NotImplementedError: | ||||||
|                     constraints = {} |                     constraints = {} | ||||||
|                 used_column_names = []  # Holds column names used in the table so far |                 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): |                 for row in connection.introspection.get_table_description(cursor, table_name): | ||||||
|                     comment_notes = []  # Holds Field notes, to be displayed in a Python comment. |                     comment_notes = []  # Holds Field notes, to be displayed in a Python comment. | ||||||
|                     extra_params = OrderedDict()  # Holds Field parameters such as 'db_column'. |                     extra_params = OrderedDict()  # Holds Field parameters such as 'db_column'. | ||||||
| @@ -85,6 +86,7 @@ class Command(BaseCommand): | |||||||
|                     comment_notes.extend(notes) |                     comment_notes.extend(notes) | ||||||
|  |  | ||||||
|                     used_column_names.append(att_name) |                     used_column_names.append(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 in indexes: | ||||||
| @@ -141,7 +143,7 @@ class Command(BaseCommand): | |||||||
|                     if comment_notes: |                     if comment_notes: | ||||||
|                         field_desc += '  # ' + ' '.join(comment_notes) |                         field_desc += '  # ' + ' '.join(comment_notes) | ||||||
|                     yield '    %s' % field_desc |                     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 |                     yield meta_line | ||||||
|  |  | ||||||
|     def normalize_col_name(self, col_name, used_column_names, is_relation): |     def normalize_col_name(self, col_name, used_column_names, is_relation): | ||||||
| @@ -238,7 +240,7 @@ class Command(BaseCommand): | |||||||
|  |  | ||||||
|         return field_type, field_params, field_notes |         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 |         Return a sequence comprising the lines of code necessary | ||||||
|         to construct the inner Meta class for the model corresponding |         to construct the inner Meta class for the model corresponding | ||||||
| @@ -251,7 +253,7 @@ class Command(BaseCommand): | |||||||
|                 if len(columns) > 1: |                 if len(columns) > 1: | ||||||
|                     # we do not want to include the u"" or u'' prefix |                     # we do not want to include the u"" or u'' prefix | ||||||
|                     # so we build the string rather than interpolate the tuple |                     # 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) |                     unique_together.append(tup) | ||||||
|         meta = ["", |         meta = ["", | ||||||
|                 "    class Meta:", |                 "    class Meta:", | ||||||
|   | |||||||
| @@ -9,4 +9,5 @@ Django 1.8.8 fixes several bugs in 1.8.7. | |||||||
| Bugfixes | Bugfixes | ||||||
| ======== | ======== | ||||||
|  |  | ||||||
| * ... | * Fixed incorrect ``unique_together`` field name generation by ``inspectdb`` | ||||||
|  |   (:ticket:`25274`). | ||||||
|   | |||||||
| @@ -73,6 +73,13 @@ class ColumnTypes(models.Model): | |||||||
| class UniqueTogether(models.Model): | class UniqueTogether(models.Model): | ||||||
|     field1 = models.IntegerField() |     field1 = models.IntegerField() | ||||||
|     field2 = models.CharField(max_length=10) |     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: |     class Meta: | ||||||
|         unique_together = ('field1', 'field2') |         unique_together = [ | ||||||
|  |             ('field1', 'field2'), | ||||||
|  |             ('from_field', 'field1'), | ||||||
|  |             ('non_unique', 'non_unique_0'), | ||||||
|  |         ] | ||||||
|   | |||||||
| @@ -226,7 +226,18 @@ class InspectDBTestCase(TestCase): | |||||||
|                      table_name_filter=lambda tn: tn.startswith('inspectdb_uniquetogether'), |                      table_name_filter=lambda tn: tn.startswith('inspectdb_uniquetogether'), | ||||||
|                      stdout=out) |                      stdout=out) | ||||||
|         output = out.getvalue() |         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', |     @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") | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user