How to use enums as a choice field in django model

后端 未结 5 1698
情书的邮戳
情书的邮戳 2020-12-30 20:06

I have a model class of which I want two fields to be a choice fields, so to populate those choices I am using an enum as listed below

#models.py
class Trans         


        
相关标签:
5条回答
  • 2020-12-30 20:21

    According to your reference from https://hackernoon.com/using-enum-as-model-field-choice-in-django-92d8b97aaa63. The choices should be list of tuple, while yours will return a tuple of tuple. More over i is different from i.name. Try:

    #enums.py
    class TransactionType(Enum):
    
        IN = "IN",
        OUT = "OUT"
    
        @classmethod
        def choices(cls):
            return [(i, i.value) for i in cls]
    
    0 讨论(0)
  • 2020-12-30 20:33

    By the way Djanog also supports the Python 3's auto() as the Enum value. You can use the following helperclass to make your life easier.

    from django.db.models.enums import TextChoices
    
    class AutoEnumChoices(TextChoices):
        def _generate_next_value_(name, start, count, last_values):  # @NoSelf
            return name.lower()
        
        @property
        def choices(cls):  # @NoSelf
            empty = [(None, cls.__empty__)] if hasattr(cls, '__empty__') else []
            return empty + [(member.value, member.label) for member in cls]
    

    Then use it in your choices definition:

    class TransferBasicStatus(AutoEnumChoices):
        NONE = auto()
        WAITING = auto()
        PENDING = auto()
        PROGRESS = auto()
        SUCCESS = auto()
        DECLINED = auto()
        ENDED =  'ended', _('Ended - The transfer has ended with mixed states')
    
    0 讨论(0)
  • 2020-12-30 20:41

    Problem in your code is that INITIATED = "INITIATED", a comma after INITIATED option and other options. when we add comma after any string it will become a tuple. See an example below

    s = 'my str'
    print(type(s))
    # output: str
    
    s = 'my str',
    print(type(s))
    # output: tuple
    

    models.py

    class Transaction(models.Model):
        trasaction_status = models.CharField(max_length=255, choices=TransactionStatus.choices())
        transaction_type = models.CharField(max_length=255, choices=TransactionType.choices())
    

    enums.py

    class TransactionType(Enum):
    
        IN = "IN"
        OUT = "OUT"
    
        @classmethod
        def choices(cls):
            print(tuple((i.name, i.value) for i in cls))
            return tuple((i.name, i.value) for i in cls)
    
    class TransactionStatus(Enum):
    
        INITIATED = "INITIATED"
        PENDING = "PENDING"
        COMPLETED = "COMPLETED"
        FAILED = "FAILED"
        ERROR = "ERROR"
    
        @classmethod
        def choices(cls):
            print(tuple((i.name, i.value) for i in cls))
            return tuple((i.name, i.value) for i in cls)
    
    0 讨论(0)
  • 2020-12-30 20:42

    For Django 2.x and lower:

    You define an Enum by setting the various options as documented here:

    class TransactionStatus(Enum):
    
        INITIATED = "INITIATED"
        PENDING = "PENDING"
        COMPLETED = "COMPLETED"
        FAILED = "FAILED"
        ERROR = "ERROR"
    

    Note there are no commas! This allows you later in your code to refer to TransactionStatus.ERROR or TransactionStatus.PENDING.

    The rest of your code is correct. You get the choices by creating tuples of option.name, option.value.

    UPDATE: For Django 3.x and higher, use the built-in types TextChoices, IntegerChoices and Choices as described here. That way you don't have to construct the choices tuple yourself.

    0 讨论(0)
  • 2020-12-30 20:47

    Django 3.0 has built-in support for Enums

    Example:

    from django.utils.translation import gettext_lazy as _
    
    class Student(models.Model):
    
        class YearInSchool(models.TextChoices):
            FRESHMAN = 'FR', _('Freshman')
            SOPHOMORE = 'SO', _('Sophomore')
            JUNIOR = 'JR', _('Junior')
            SENIOR = 'SR', _('Senior')
            GRADUATE = 'GR', _('Graduate')
    
        year_in_school = models.CharField(
            max_length=2,
            choices=YearInSchool.choices,
            default=YearInSchool.FRESHMAN,
        )
    

    These work similar to enum from Python’s standard library, but with some modifications:

    • Enum member values are a tuple of arguments to use when constructing the concrete data type. Django supports adding an extra string value to the end of this tuple to be used as the human-readable name, or label. The label can be a lazy translatable string. Thus, in most cases, the member value will be a (value, label) two-tuple. If a tuple is not provided, or the last item is not a (lazy) string, the label is automatically generated from the member name.
    • A .label property is added on values, to return the human-readable name. A number of custom properties are added to the enumeration classes – .choices, .labels, .values, and .names – to make it easier to access lists of those separate parts of the enumeration. Use .choices as a suitable value to pass to choices in a field definition.
    • The use of enum.unique() is enforced to ensure that values cannot be defined multiple times. This is unlikely to be expected in choices for a field.

    For more info, check the documentation

    0 讨论(0)
提交回复
热议问题