mirror of
https://github.com/django/django.git
synced 2025-11-18 19:01:40 +00:00
Fix makemigrations path for inner/nested classes
Use __qualname__ to serialize inner classes with their full path, ensuring migrations reference the correct containing class. Fixes incorrect migration code for nested fields and Enums.
This commit is contained in:
parent
89d41cba39
commit
ad96210192
2 changed files with 40 additions and 3 deletions
|
|
@ -143,7 +143,7 @@ class FunctionTypeSerializer(BaseSerializer):
|
|||
if getattr(self.value, "__self__", None) and isinstance(self.value.__self__, type):
|
||||
klass = self.value.__self__
|
||||
module = klass.__module__
|
||||
return "%s.%s.%s" % (module, klass.__name__, self.value.__name__), {"import %s" % module}
|
||||
return "%s.%s.%s" % (module, klass.__qualname__, self.value.__name__), {"import %s" % module}
|
||||
# Further error checking
|
||||
if self.value.__name__ == '<lambda>':
|
||||
raise ValueError("Cannot serialize function: lambda")
|
||||
|
|
@ -269,7 +269,7 @@ class TypeSerializer(BaseSerializer):
|
|||
if module == builtins.__name__:
|
||||
return self.value.__name__, set()
|
||||
else:
|
||||
return "%s.%s" % (module, self.value.__name__), {"import %s" % module}
|
||||
return "%s.%s" % (module, self.value.__qualname__), {"import %s" % module}
|
||||
|
||||
|
||||
class UUIDSerializer(BaseSerializer):
|
||||
|
|
|
|||
|
|
@ -61,6 +61,14 @@ class IntEnum(enum.IntEnum):
|
|||
B = 2
|
||||
|
||||
|
||||
class OuterClass:
|
||||
"""Module-level outer class for testing nested class serialization."""
|
||||
class InnerClass(models.CharField):
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs.setdefault('max_length', 20)
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
class OperationWriterTests(SimpleTestCase):
|
||||
|
||||
def test_empty_signature(self):
|
||||
|
|
@ -731,7 +739,13 @@ class WriterTests(SimpleTestCase):
|
|||
return ('DeconstructibleInstances', [], {})
|
||||
|
||||
string = MigrationWriter.serialize(models.CharField(default=DeconstructibleInstances))[0]
|
||||
self.assertEqual(string, "models.CharField(default=migrations.test_writer.DeconstructibleInstances)")
|
||||
# Since DeconstructibleInstances is defined locally (in a function), it will have
|
||||
# '<locals>' in its __qualname__, resulting in a fully qualified path
|
||||
self.assertEqual(
|
||||
string,
|
||||
"models.CharField(default=migrations.test_writer.WriterTests."
|
||||
"test_deconstruct_class_arguments.<locals>.DeconstructibleInstances)"
|
||||
)
|
||||
|
||||
def test_register_serializer(self):
|
||||
class ComplexSerializer(BaseSerializer):
|
||||
|
|
@ -747,3 +761,26 @@ class WriterTests(SimpleTestCase):
|
|||
def test_register_non_serializer(self):
|
||||
with self.assertRaisesMessage(ValueError, "'TestModel1' must inherit from 'BaseSerializer'."):
|
||||
MigrationWriter.register_serializer(complex, TestModel1)
|
||||
|
||||
def test_serialize_nested_class(self):
|
||||
"""
|
||||
Test serialization of nested/inner classes.
|
||||
When a custom field is defined as an inner class, the serializer should
|
||||
use the full qualified name including the outer class.
|
||||
Regression test for issue where makemigrations incorrectly serialized
|
||||
inner classes without their outer class qualifier.
|
||||
"""
|
||||
# Test serializing the type itself
|
||||
string, imports = MigrationWriter.serialize(OuterClass.InnerClass)
|
||||
self.assertEqual(string, "migrations.test_writer.OuterClass.InnerClass")
|
||||
self.assertEqual(imports, {"import migrations.test_writer"})
|
||||
|
||||
# Test serializing an instance of the nested field
|
||||
field = OuterClass.InnerClass(max_length=20)
|
||||
string, imports = MigrationWriter.serialize(field)
|
||||
# The field instance should reference the correct nested class path
|
||||
self.assertIn("migrations.test_writer.OuterClass.InnerClass", string)
|
||||
|
||||
# The serialized string should NOT be just "InnerClass" without the outer class
|
||||
self.assertNotIn("models.InnerClass", string)
|
||||
self.assertNotIn("test_writer.InnerClass(", string)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue