From 16fffc829cbcb231b7276d7e1d0bb836a515873b Mon Sep 17 00:00:00 2001 From: Willem Van Onsem Date: Thu, 11 Aug 2022 18:17:19 +0200 Subject: [PATCH] Fixed #33916 -- Added support for serialization of enum.Flag in migrations. --- django/db/migrations/serializer.py | 17 +++++++++++++++-- docs/releases/4.2.txt | 2 +- docs/topics/migrations.txt | 6 +++++- tests/migrations/test_writer.py | 8 ++++++++ 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/django/db/migrations/serializer.py b/django/db/migrations/serializer.py index 38da1e6ecc..7ebc966f40 100644 --- a/django/db/migrations/serializer.py +++ b/django/db/migrations/serializer.py @@ -16,7 +16,7 @@ from django.db import models from django.db.migrations.operations.base import Operation from django.db.migrations.utils import COMPILED_REGEX_TYPE, RegexObject from django.utils.functional import LazyObject, Promise -from django.utils.version import get_docs_version +from django.utils.version import PY311, get_docs_version class BaseSerializer: @@ -125,8 +125,21 @@ class EnumSerializer(BaseSerializer): def serialize(self): enum_class = self.value.__class__ module = enum_class.__module__ + if issubclass(enum_class, enum.Flag): + if PY311: + members = list(self.value) + else: + members, _ = enum._decompose(enum_class, self.value) + members = reversed(members) + else: + members = (self.value,) return ( - "%s.%s[%r]" % (module, enum_class.__qualname__, self.value.name), + " | ".join( + [ + f"{module}.{enum_class.__qualname__}[{item.name!r}]" + for item in members + ] + ), {"import %s" % module}, ) diff --git a/docs/releases/4.2.txt b/docs/releases/4.2.txt index d7e40f600b..e4961fba2f 100644 --- a/docs/releases/4.2.txt +++ b/docs/releases/4.2.txt @@ -192,7 +192,7 @@ Management Commands Migrations ~~~~~~~~~~ -* ... +* Migrations now support serialization of ``enum.Flag`` objects. Models ~~~~~~ diff --git a/docs/topics/migrations.txt b/docs/topics/migrations.txt index cf3451a782..e67e074886 100644 --- a/docs/topics/migrations.txt +++ b/docs/topics/migrations.txt @@ -739,7 +739,7 @@ Django can serialize the following: - ``datetime.date``, ``datetime.time``, and ``datetime.datetime`` instances (include those that are timezone-aware) - ``decimal.Decimal`` instances -- ``enum.Enum`` instances +- ``enum.Enum`` and ``enum.Flag`` instances - ``uuid.UUID`` instances - :func:`functools.partial` and :class:`functools.partialmethod` instances which have serializable ``func``, ``args``, and ``keywords`` values. @@ -756,6 +756,10 @@ Django can serialize the following: - Any class reference (must be in module's top-level scope) - Anything with a custom ``deconstruct()`` method (:ref:`see below `) +.. versionchanged:: 4.2 + + Serialization support for ``enum.Flag`` was added. + Django cannot serialize: - Nested classes diff --git a/tests/migrations/test_writer.py b/tests/migrations/test_writer.py index bad8775d4e..2a965ef7e0 100644 --- a/tests/migrations/test_writer.py +++ b/tests/migrations/test_writer.py @@ -413,6 +413,14 @@ class WriterTests(SimpleTestCase): "(2, migrations.test_writer.IntFlagEnum['B'])], " "default=migrations.test_writer.IntFlagEnum['A'])", ) + self.assertSerializedResultEqual( + IntFlagEnum.A | IntFlagEnum.B, + ( + "migrations.test_writer.IntFlagEnum['A'] | " + "migrations.test_writer.IntFlagEnum['B']", + {"import migrations.test_writer"}, + ), + ) def test_serialize_choices(self): class TextChoices(models.TextChoices):