Наследовать класс Django choice, чтобы расширить его?

У меня есть поле в моем models.py, которое принимает варианты, определенные в классе:

from apps.users.constants import UserChoices


class User(models.Model):
    choices = models.CharField(max_length=10, blank=True, choices=UserChoices.choices(), default=UserChoices.PUBLIC)

Класс выбора таков:

from django.utils.translation import ugettext_lazy as _


class UserChoices:
    PRIVATE_USER = "private_user"
    PUBLIC_USER = "public_user"

    @classmethod
    def choices(cls):
        return (
            (cls.PRIVATE_USER, _("Private User)),
            (cls.PUBLIC_USER, _("Public User"),
        )

Мои сомнения в том, как я могу наследовать этот класс UserChoices другому классу выбора, чтобы расширить его другими вариантами.

Я попробовал следующее:

class ExtendedChoices(UserChoices):

    OTHER_CHOICE = "other_choice"

    @classmethod
    def choices(cls):
        return (
            UserChoices.choices(),
            (cls.OTHER_CHOICE, _("Other choice")),
        )

Но это дает мне ошибку миграции:

steps.StepVisibility.gender: (fields.E005) 'choices' must be an iterable containing (actual value, human readable name) tuples.

Очевидно, что этот пример упрощен, реальный код имеет 40+ вариантов в оригинальном классе и 20+ в расширенном.

Вам нужно распаковать те из них, которые находятся у родителя. Вы делаете это с помощью asterisk (*):

class ExtendedChoices(UserChoices):

    OTHER_CHOICE = "other_choice"

    @classmethod
    def choices(cls):
        return (
            *UserChoices.choices(),  # ← an asterisk to unpack the tuple
            (cls.OTHER_CHOICE, _("Other choice")),
        )

Если мы распаковываем кортеж в другой кортеж, мы строим кортеж, который содержит все элементы распакованного кортежа как элементы нового кортежа. Например:

>>> x = (1,4,2)
>>> (x, 5)
((1, 4, 2), 5)
>>> (*x, 5)
(1, 4, 2, 5)

Если не использовать звездочку, то x будет восприниматься как кортеж, и мы построим 2-кортеж, первым элементом которого будет кортеж x.

Если мы распакуем первый кортеж, то получим 4 кортежа, где первые три элемента происходят из x, а затем из 5.

Вернуться на верх