I have a field in my models.py that accepts choices determined in a class:
from apps.users.constants import UserChoices
class User(models.Model):
choices = models.CharField(max_length=10, blank=True, choices=UserChoices.choices(), default=UserChoices.PUBLIC_USER)
The choice class is this:
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")),
)
My doubt is how can I inherit this UserChoices class to another choice class, in order to extend it with another options.
I tried the following:
class ExtendedChoices(UserChoices):
OTHER_CHOICE = "other_choice"
@classmethod
def choices(cls):
return (
UserChoices.choices(),
(cls.OTHER_CHOICE, _("Other choice")),
)
But it gives me a migration error:
users.OtherModel.other_choice: (fields.E005) 'choices' must be an iterable containing (actual value, human readable name) tuples.
Obviously this example is simplified, the actual code has 40 choices on the original class and 20 in the extended one.
CodePudding user response:
You need to unpack the ones from the parent. You do that with an 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")),
)
If we unpack a tuple in another tuple, we construct a tuple that contains all the items of the unpacked tuple as elements of the new tuple. For example:
>>> x = (1,4,2)
>>> (x, 5)
((1, 4, 2), 5)
>>> (*x, 5)
(1, 4, 2, 5)
If we thus do not use an asterisk, it will simply see x
as a tuple, and we thus construct a 2-tuple with as first element the tuple x
.
If we unpack the first tuple, we obtain a 4-tuple where the first three elements originate from x
followed by 5
.