Django TextChoices Behavior

Viewed 4234
class MyTypes(TextChoices):
    MINE_AAA = '1', 'a',
    MINE_BBB = '2', 'b',
    MINE_CCC = '3', 'c',
    MINE_DDD = '4', 'd',
    MINE_EEE = '5', 'e'

    my_type = models.CharField(max_length=1, choices=MyTypes.choices)

I have been struggling a lot with being able to use Choices in my models. With the above example, if I create an instance "my_obj" and set "my_obj.my_type" to "MyTypes.MINE_BBB", the if I look at the "my_obj", its type is MyTypes. However, if I later query "my_obj" and look at "my_obj.my_type", its type is now a string.

So, when I create the object initially and serialize it, the serializer needs to handle MyTypes, but if I serialize the value after a query, the serializer needs to handle a string.

What I was really expecting when using a TextChoices field was that the value stored in the Database would be the single character, but when I reference it in code, I would see my MyTypes.

Are we not supposed to get the TextChoices instance back when we reference the model? If not, what is the simplest way to get it? It seem that if I after iterate through the MyTypes.choices to get it, that it really doesn't provide much value.

Here is what the documentation looks like.

class YearInSchool(models.TextChoices):
        FRESHMAN = 'FR', _('Freshman')
        SOPHOMORE = 'SO', _('Sophomore')
        JUNIOR = 'JR', _('Junior')
        SENIOR = 'SR', _('Senior')
        GRADUATE = 'GR', _('Graduate')
3 Answers

You can get the MyTypes instance like so:

MyTypes('1') == MyTypes.MINE_AAA

So in your code, whenever you want the type of my_obj, as a MyTypes instance you can do MyType(my_obj.my_type).

I recommend writing a method for it:

class MyModel(models.model):
    class MyType(TextChoices):
        ...

    my_type = models.CharField(max_length=1, choices=MyTypes.choices)

    def get_type(self):
        return MyModel.MyType(self.my_type)

the choices field need to be a list of tuple

class MyTypes(TextChoices):
    MINE_AAA = ('1', 'a',)
    MINE_BBB = ('2', 'b',)
    MINE_CCC = ('3', 'c',)
    MINE_DDD = ('4', 'd',)
    MINE_EEE = ('5', 'e')

    MY_CHOICES = [
        MINE_AAA,
        MINE_BBB,
        MINE_CCC,
        MINE_DDD,
        MINE_EEE
    ]

    my_type = models.CharField(max_length=1, choices=MY_CHOICES)

Here is what the documentation looks like.

class YearInSchool(models.TextChoices):
        FRESHMAN = 'FR', _('Freshman')
        SOPHOMORE = 'SO', _('Sophomore')
        JUNIOR = 'JR', _('Junior')
        SENIOR = 'SR', _('Senior')
        GRADUATE = 'GR', _('Graduate')

TextChoice for Gender Selection, first of all you have to import

from django.utils.translation import gettext_lazy as _

class Gender(models.TextChoices):
    MALE = "male", _("Male")
    FEMALE = "female", _("Female")
    OTHER = "other", _("Other")
Related