mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Fixed #24817 -- Prevented loss of null info in MySQL field renaming.
This commit is contained in:
		
				
					committed by
					
						 Tim Graham
						Tim Graham
					
				
			
			
				
	
			
			
			
						parent
						
							300e8baf94
						
					
				
				
					commit
					80ad5472ce
				
			| @@ -542,12 +542,7 @@ class BaseDatabaseSchemaEditor(object): | ||||
|                 self.execute(self._delete_constraint_sql(self.sql_delete_check, model, constraint_name)) | ||||
|         # Have they renamed the column? | ||||
|         if old_field.column != new_field.column: | ||||
|             self.execute(self.sql_rename_column % { | ||||
|                 "table": self.quote_name(model._meta.db_table), | ||||
|                 "old_column": self.quote_name(old_field.column), | ||||
|                 "new_column": self.quote_name(new_field.column), | ||||
|                 "type": new_type, | ||||
|             }) | ||||
|             self.execute(self._rename_field_sql(model._meta.db_table, old_field, new_field, new_type)) | ||||
|         # Next, start accumulating actions to do | ||||
|         actions = [] | ||||
|         null_actions = [] | ||||
| @@ -864,6 +859,14 @@ class BaseDatabaseSchemaEditor(object): | ||||
|             output.append(self._create_index_sql(model, fields, suffix="_idx")) | ||||
|         return output | ||||
|  | ||||
|     def _rename_field_sql(self, table, old_field, new_field, new_type): | ||||
|         return self.sql_rename_column % { | ||||
|             "table": self.quote_name(table), | ||||
|             "old_column": self.quote_name(old_field.column), | ||||
|             "new_column": self.quote_name(new_field.column), | ||||
|             "type": new_type, | ||||
|         } | ||||
|  | ||||
|     def _create_fk_sql(self, model, field, suffix): | ||||
|         from_table = model._meta.db_table | ||||
|         from_column = field.column | ||||
|   | ||||
| @@ -80,10 +80,21 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor): | ||||
|                 ) | ||||
|         return super(DatabaseSchemaEditor, self)._delete_composed_index(model, fields, *args) | ||||
|  | ||||
|     def _alter_column_type_sql(self, table, old_field, new_field, new_type): | ||||
|         # Keep null property of old field, if it has changed, it will be handled separately | ||||
|         if old_field.null: | ||||
|     def _set_field_new_type_null_status(self, field, new_type): | ||||
|         """ | ||||
|         Keep the null property of the old field. If it has changed, it will be | ||||
|         handled separately. | ||||
|         """ | ||||
|         if field.null: | ||||
|             new_type += " NULL" | ||||
|         else: | ||||
|             new_type += " NOT NULL" | ||||
|         return new_type | ||||
|  | ||||
|     def _alter_column_type_sql(self, table, old_field, new_field, new_type): | ||||
|         new_type = self._set_field_new_type_null_status(old_field, new_type) | ||||
|         return super(DatabaseSchemaEditor, self)._alter_column_type_sql(table, old_field, new_field, new_type) | ||||
|  | ||||
|     def _rename_field_sql(self, table, old_field, new_field, new_type): | ||||
|         new_type = self._set_field_new_type_null_status(old_field, new_type) | ||||
|         return super(DatabaseSchemaEditor, self)._rename_field_sql(table, old_field, new_field, new_type) | ||||
|   | ||||
							
								
								
									
										10
									
								
								docs/releases/1.7.9.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								docs/releases/1.7.9.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| ========================== | ||||
| Django 1.7.9 release notes | ||||
| ========================== | ||||
|  | ||||
| *Under development* | ||||
|  | ||||
| Django 1.7.9 fixes several bugs in 1.7.8. | ||||
|  | ||||
| * Prevented the loss of ``null``/``not null`` column properties during field | ||||
|   renaming of MySQL databases (:ticket:`24817`). | ||||
| @@ -25,3 +25,6 @@ Bugfixes | ||||
|  | ||||
| * Fixed a regression which caused template context processors to overwrite | ||||
|   variables set on a ``RequestContext`` after it's created (:ticket:`24847`). | ||||
|  | ||||
| * Prevented the loss of ``null``/``not null`` column properties during field | ||||
|   renaming of MySQL databases (:ticket:`24817`). | ||||
|   | ||||
| @@ -42,6 +42,7 @@ versions of the documentation contain the release notes for any later releases. | ||||
| .. toctree:: | ||||
|    :maxdepth: 1 | ||||
|  | ||||
|    1.7.9 | ||||
|    1.7.8 | ||||
|    1.7.7 | ||||
|    1.7.6 | ||||
|   | ||||
| @@ -87,6 +87,14 @@ class Note(models.Model): | ||||
|         apps = new_apps | ||||
|  | ||||
|  | ||||
| class NoteRename(models.Model): | ||||
|     detail_info = models.TextField() | ||||
|  | ||||
|     class Meta: | ||||
|         apps = new_apps | ||||
|         db_table = "schema_note" | ||||
|  | ||||
|  | ||||
| class Tag(models.Model): | ||||
|     title = models.CharField(max_length=255) | ||||
|     slug = models.SlugField(unique=True) | ||||
|   | ||||
| @@ -20,8 +20,8 @@ from django.test import TransactionTestCase, skipIfDBFeature | ||||
| from .fields import CustomManyToManyField, InheritedManyToManyField | ||||
| from .models import ( | ||||
|     Author, AuthorWithDefaultHeight, AuthorWithEvenLongerName, Book, BookWeak, | ||||
|     BookWithLongName, BookWithO2O, BookWithSlug, Note, Tag, TagIndexed, | ||||
|     TagM2MTest, TagUniqueRename, Thing, UniqueTest, new_apps, | ||||
|     BookWithLongName, BookWithO2O, BookWithSlug, Note, NoteRename, Tag, | ||||
|     TagIndexed, TagM2MTest, TagUniqueRename, Thing, UniqueTest, new_apps, | ||||
| ) | ||||
|  | ||||
|  | ||||
| @@ -751,6 +751,26 @@ class SchemaTests(TransactionTestCase): | ||||
|         self.assertEqual(columns['display_name'][0], "CharField") | ||||
|         self.assertNotIn("name", columns) | ||||
|  | ||||
|     @skipIfDBFeature('interprets_empty_strings_as_nulls') | ||||
|     def test_rename_keep_null_status(self): | ||||
|         """ | ||||
|         Renaming a field shouldn't affect the not null status. | ||||
|         """ | ||||
|         with connection.schema_editor() as editor: | ||||
|             editor.create_model(Note) | ||||
|         with self.assertRaises(IntegrityError): | ||||
|             Note.objects.create(info=None) | ||||
|         old_field = Note._meta.get_field("info") | ||||
|         new_field = TextField() | ||||
|         new_field.set_attributes_from_name("detail_info") | ||||
|         with connection.schema_editor() as editor: | ||||
|             editor.alter_field(Note, old_field, new_field, strict=True) | ||||
|         columns = self.column_classes(Note) | ||||
|         self.assertEqual(columns['detail_info'][0], "TextField") | ||||
|         self.assertNotIn("info", columns) | ||||
|         with self.assertRaises(IntegrityError): | ||||
|             NoteRename.objects.create(detail_info=None) | ||||
|  | ||||
|     def _test_m2m_create(self, M2MFieldClass): | ||||
|         """ | ||||
|         Tests M2M fields on models during creation | ||||
|   | ||||
		Reference in New Issue
	
	Block a user