web-dev-qa-db-ja.com

列挙型をDjangoモデルの選択フィールドとして使用する方法

2つのフィールドを選択肢フィールドにしたいモデルクラスがあるので、これらの選択肢にデータを入力するには、以下の列挙型を使用します。

#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)

しかし、管理者を介してこのモデルにアクセスしようとすると、次のエラーが発生します。

Django Version: 1.11
Exception Type: ValueError
Exception Value:    
too many values to unpack (expected 2)

列挙型の使用方法を説明した2つの記事に従いました。

16
Paras

Django 2.x以下の場合:

Enumを定義するには、ドキュメントに記載されているようにさまざまなオプションを設定します here

class TransactionStatus(Enum):

    INITIATED = "INITIATED"
    PENDING = "PENDING"
    COMPLETED = "COMPLETED"
    FAILED = "FAILED"
    ERROR = "ERROR"

コンマがないことに注意してください!これにより、後でコードでTransactionStatus.ERRORまたはTransactionStatus.PENDINGを参照できます。

コードの残りの部分は正しいです。 choicesを取得するには、option.nameoption.valueのタプルを作成します。

更新:Django 3.x以降)の場合、組み込み型TextChoicesを使用します説明されているようにIntegerChoicesおよびChoiceshere 。そうすれば、自分でchoicesタプルを構築する必要はありません。

9
dirkgroten

Django 3.0にはEnumのサポートが組み込まれています

例:

_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,
    )
_

これらは、Pythonの標準ライブラリの enum に似ていますが、いくつかの変更点があります。

  • 列挙型メンバー値は、具象データ型を構築するときに使用する引数のタプルです。 Djangoは、このタプルの末尾に追加の文字列値を追加して、人間が読める名前として使用できるようにするか、labelです。labelは、遅延翻訳可能な文字列。したがって、ほとんどの場合、メンバー値は_(value, label)_の2つのタプルになります。タプルが指定されていない場合、または最後の項目が(遅延)文字列でない場合、ラベルは 自動生成 メンバー名から。
  • _.label_プロパティが値に追加され、人間が読める名前が返されます。列挙型クラスに_.choices_、_.labels_、_.values_、および_.names_のカスタムプロパティが追加され、列挙。フィールド定義の選択肢に渡す適切な値として_.choices_を使用します。
  • enum.unique() の使用は、値が複数回定義されないようにするために強制されます。これは、フィールドの選択で期待されることはほとんどありません。

詳しくは ドキュメントを確認

22
Cesar Canassa

コードの問題はINITIATED = "INITIATED",INITIATEDオプションおよびその他のオプションの後ろのコンマ。文字列の後にコンマを追加すると、タプルになります。以下の例をご覧ください

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)
2