mirror of
				https://github.com/django/django.git
				synced 2025-10-29 00:26:07 +00:00 
			
		
		
		
	[1.7.x] Fixed #23418 -- Fail when migration deconstruct produces invalid import
Backport of d28b5f13b3 from master
			
			
This commit is contained in:
		
				
					committed by
					
						 Tim Graham
						Tim Graham
					
				
			
			
				
	
			
			
			
						parent
						
							9c4fb019cb
						
					
				
				
					commit
					b0def3bcac
				
			| @@ -1,3 +1,5 @@ | |||||||
|  | from importlib import import_module | ||||||
|  |  | ||||||
| def deconstructible(*args, **kwargs): | def deconstructible(*args, **kwargs): | ||||||
|     """ |     """ | ||||||
|     Class decorator that allow the decorated class to be serialized |     Class decorator that allow the decorated class to be serialized | ||||||
| @@ -19,8 +21,25 @@ def deconstructible(*args, **kwargs): | |||||||
|             Returns a 3-tuple of class import path, positional arguments, |             Returns a 3-tuple of class import path, positional arguments, | ||||||
|             and keyword arguments. |             and keyword arguments. | ||||||
|             """ |             """ | ||||||
|  |             # Python 2/fallback version | ||||||
|  |             if path: | ||||||
|  |                 module_name, _, name = path.rpartition('.') | ||||||
|  |             else: | ||||||
|  |                 module_name = obj.__module__ | ||||||
|  |                 name = obj.__class__.__name__ | ||||||
|  |             # Make sure it's actually there and not an inner class | ||||||
|  |             module = import_module(module_name) | ||||||
|  |             if not hasattr(module, name): | ||||||
|  |                 raise ValueError( | ||||||
|  |                     "Could not find object %s in %s.\n" | ||||||
|  |                     "Please note that you cannot serialize things like inner " | ||||||
|  |                     "classes. Please move the object into the main module " | ||||||
|  |                     "body to use migrations.\n" | ||||||
|  |                     "For more information, see " | ||||||
|  |                     "https://docs.djangoproject.com/en/dev/topics/migrations/#serializing-values" | ||||||
|  |                     % (name, module_name)) | ||||||
|             return ( |             return ( | ||||||
|                 path or '%s.%s' % (obj.__class__.__module__, obj.__class__.__name__), |                 path or '%s.%s' % (obj.__class__.__module__, name), | ||||||
|                 obj._constructor_args[0], |                 obj._constructor_args[0], | ||||||
|                 obj._constructor_args[1], |                 obj._constructor_args[1], | ||||||
|             ) |             ) | ||||||
|   | |||||||
| @@ -20,3 +20,6 @@ Bugfixes | |||||||
| * Fixed serialization of ``type`` objects in migrations (:ticket:`22951`). | * Fixed serialization of ``type`` objects in migrations (:ticket:`22951`). | ||||||
|  |  | ||||||
| * Allowed inline and hidden references to admin fields (:ticket:`23431`). | * Allowed inline and hidden references to admin fields (:ticket:`23431`). | ||||||
|  |  | ||||||
|  | * The ``@deconstructible`` decorator now fails with a ``ValueError`` if the | ||||||
|  |   decorated object cannot automatically be imported (:ticket:`23418`). | ||||||
|   | |||||||
| @@ -167,9 +167,17 @@ class WriterTests(TestCase): | |||||||
|         self.assertEqual(string, "django.core.validators.EmailValidator(message='hello')") |         self.assertEqual(string, "django.core.validators.EmailValidator(message='hello')") | ||||||
|         self.serialize_round_trip(validator) |         self.serialize_round_trip(validator) | ||||||
|  |  | ||||||
|         validator = deconstructible(path="custom.EmailValidator")(EmailValidator)(message="hello") |         validator = deconstructible(path="migrations.test_writer.EmailValidator")(EmailValidator)(message="hello") | ||||||
|         string = MigrationWriter.serialize(validator)[0] |         string = MigrationWriter.serialize(validator)[0] | ||||||
|         self.assertEqual(string, "custom.EmailValidator(message='hello')") |         self.assertEqual(string, "migrations.test_writer.EmailValidator(message='hello')") | ||||||
|  |  | ||||||
|  |         validator = deconstructible(path="custom.EmailValidator")(EmailValidator)(message="hello") | ||||||
|  |         with self.assertRaisesMessage(ImportError, "No module named 'custom'"): | ||||||
|  |             MigrationWriter.serialize(validator) | ||||||
|  |  | ||||||
|  |         validator = deconstructible(path="django.core.validators.EmailValidator2")(EmailValidator)(message="hello") | ||||||
|  |         with self.assertRaisesMessage(ValueError, "Could not find object EmailValidator2 in django.core.validators."): | ||||||
|  |             MigrationWriter.serialize(validator) | ||||||
|  |  | ||||||
|     def test_serialize_empty_nonempty_tuple(self): |     def test_serialize_empty_nonempty_tuple(self): | ||||||
|         """ |         """ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user