Наследовать класс 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
.