mirror of
https://github.com/django/django.git
synced 2025-11-19 03:08:59 +00:00
Fix migration enum serialization to use enum name, not value
Ensure migrations use enum names for CharFields to avoid errors with translatable values. This prevents migration failures when enum values are translated, addressing issues with Django's translation framework and Enum usage.
This commit is contained in:
parent
e02f67ef2d
commit
745e0d9437
2 changed files with 42 additions and 11 deletions
|
|
@ -120,9 +120,16 @@ class EnumSerializer(BaseSerializer):
|
|||
def serialize(self):
|
||||
enum_class = self.value.__class__
|
||||
module = enum_class.__module__
|
||||
v_string, v_imports = serializer_factory(self.value.value).serialize()
|
||||
imports = {'import %s' % module, *v_imports}
|
||||
return "%s.%s(%s)" % (module, enum_class.__name__, v_string), imports
|
||||
# For IntEnum and IntFlag, the value is stable and should be used directly
|
||||
# For other Enum types, use name-based access to handle mutable values
|
||||
# (like translatable strings) that may change between runs
|
||||
if isinstance(self.value, (enum.IntEnum, enum.IntFlag)):
|
||||
v_string, v_imports = serializer_factory(self.value.value).serialize()
|
||||
imports = {'import %s' % module, *v_imports}
|
||||
return "%s.%s(%s)" % (module, enum_class.__name__, v_string), imports
|
||||
else:
|
||||
imports = {'import %s' % module}
|
||||
return "%s.%s[%r]" % (module, enum_class.__name__, self.value.name), imports
|
||||
|
||||
|
||||
class FloatSerializer(BaseSimpleSerializer):
|
||||
|
|
|
|||
|
|
@ -267,11 +267,11 @@ class WriterTests(SimpleTestCase):
|
|||
|
||||
self.assertSerializedResultEqual(
|
||||
TextEnum.A,
|
||||
("migrations.test_writer.TextEnum('a-value')", {'import migrations.test_writer'})
|
||||
("migrations.test_writer.TextEnum['A']", {'import migrations.test_writer'})
|
||||
)
|
||||
self.assertSerializedResultEqual(
|
||||
BinaryEnum.A,
|
||||
("migrations.test_writer.BinaryEnum(b'a-value')", {'import migrations.test_writer'})
|
||||
("migrations.test_writer.BinaryEnum['A']", {'import migrations.test_writer'})
|
||||
)
|
||||
self.assertSerializedResultEqual(
|
||||
IntEnum.B,
|
||||
|
|
@ -283,18 +283,18 @@ class WriterTests(SimpleTestCase):
|
|||
self.assertEqual(
|
||||
string,
|
||||
"models.CharField(choices=["
|
||||
"('a-value', migrations.test_writer.TextEnum('a-value')), "
|
||||
"('value-b', migrations.test_writer.TextEnum('value-b'))], "
|
||||
"default=migrations.test_writer.TextEnum('value-b'))"
|
||||
"('a-value', migrations.test_writer.TextEnum['A']), "
|
||||
"('value-b', migrations.test_writer.TextEnum['B'])], "
|
||||
"default=migrations.test_writer.TextEnum['B'])"
|
||||
)
|
||||
field = models.CharField(default=BinaryEnum.B, choices=[(m.value, m) for m in BinaryEnum])
|
||||
string = MigrationWriter.serialize(field)[0]
|
||||
self.assertEqual(
|
||||
string,
|
||||
"models.CharField(choices=["
|
||||
"(b'a-value', migrations.test_writer.BinaryEnum(b'a-value')), "
|
||||
"(b'value-b', migrations.test_writer.BinaryEnum(b'value-b'))], "
|
||||
"default=migrations.test_writer.BinaryEnum(b'value-b'))"
|
||||
"(b'a-value', migrations.test_writer.BinaryEnum['A']), "
|
||||
"(b'value-b', migrations.test_writer.BinaryEnum['B'])], "
|
||||
"default=migrations.test_writer.BinaryEnum['B'])"
|
||||
)
|
||||
field = models.IntegerField(default=IntEnum.A, choices=[(m.value, m) for m in IntEnum])
|
||||
string = MigrationWriter.serialize(field)[0]
|
||||
|
|
@ -306,6 +306,30 @@ class WriterTests(SimpleTestCase):
|
|||
"default=migrations.test_writer.IntEnum(1))"
|
||||
)
|
||||
|
||||
def test_serialize_enums_with_translated_values(self):
|
||||
"""
|
||||
Test that enum serialization uses name-based access instead of
|
||||
value-based constructor to handle translatable enum values.
|
||||
"""
|
||||
class TranslatedEnum(enum.Enum):
|
||||
GOOD = _('Good')
|
||||
BAD = _('Bad')
|
||||
|
||||
# Enum should be serialized using name-based access
|
||||
self.assertSerializedResultEqual(
|
||||
TranslatedEnum.GOOD,
|
||||
("migrations.test_writer.TranslatedEnum['GOOD']", {'import migrations.test_writer'})
|
||||
)
|
||||
self.assertSerializedResultEqual(
|
||||
TranslatedEnum.BAD,
|
||||
("migrations.test_writer.TranslatedEnum['BAD']", {'import migrations.test_writer'})
|
||||
)
|
||||
|
||||
# Test with a field
|
||||
field = models.CharField(default=TranslatedEnum.GOOD, max_length=128)
|
||||
string = MigrationWriter.serialize(field)[0]
|
||||
self.assertIn("default=migrations.test_writer.TranslatedEnum['GOOD']", string)
|
||||
|
||||
def test_serialize_choices(self):
|
||||
class TextChoices(models.TextChoices):
|
||||
A = 'A', 'A value'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue