Другое

Как правильно задавать параметры в Django TextChoices

Узнайте, как правильно использовать blank и __empty__ в Django TextChoices, чтобы избежать TypeError и добавить пустые варианты выбора.

Как правильно задать параметры в Django TextChoices? При попытке использования кода:

python
sex = models.TextChoices('M', 'Ж', blank=True)

возникает ошибка:

TypeError: EnumType.__call__() got an unexpected keyword argument 'blank'

Ошибка возникает потому что параметр blank не предназначен для передачи в конструктор TextChoices. Этот параметр должен быть указан непосредственно в поле модели, а не в классе выбора. Для добавления пустого варианта в TextChoices используется специальный атрибут __empty__.


Содержание


Основные параметры TextChoices

TextChoices в Django — это современный способ определения вариантов выбора для полей модели. Основной синтаксис выглядит так:

python
class Status(models.TextChoices):
    DRAFT = 'draft', 'Черновик'
    PUBLISHED = 'published', 'Опубликовано'
    ARCHIVED = 'archived', 'Архив'

Ключевые моменты:

  • Первый элемент кортежа — значение, которое сохранится в базе данных
  • Второй элемент — отображаемое имя
  • Класс должен наследоваться от models.TextChoices
  • Доступ к вариантам выбора через атрибут .choices

Правильное использование blank

Ошибка TypeError: EnumType.__call__() got an unexpected keyword argument 'blank' возникает потому что blank — это параметр для полей модели, а не для TextChoices. Правильная реализация:

python
class Sex(models.TextChoices):
    MALE = 'M', 'Мужской'
    FEMALE = 'F', 'Женский'

class Person(models.Model):
    sex = models.CharField(
        max_length=1, 
        choices=Sex.choices, 
        blank=True  # Вот здесь должен быть blank, а не в TextChoices
    )

Параметр blank=True в поле модели разрешает пустые значения в формах, но не влияет на базу данных. Для сохранения NULL в базе нужно дополнительно использовать null=True.


Добавление пустого варианта с empty

В Django 3.0+ есть удобный способ добавить пустой вариант прямо в класс TextChoices с помощью атрибута __empty__:

python
class Sex(models.TextChoices):
    MALE = 'M', 'Мужской'
    FEMALE = 'F', 'Женский'
    __empty__ = 'Не указан'  # Элемент будет добавлен в начало списка

Этот подход автоматически добавит пустой вариант в начало списка выбора. Важно, что значение __empty__ может быть любой строкой, которая будет отображаться в интерфейсе.

Пример использования:

python
class Person(models.Model):
    sex = models.CharField(
        max_length=1,
        choices=Sex.choices,
        blank=True,
        default=''  # Можно задать пустое значение по умолчанию
    )

Полные примеры кода

Пример 1: Базовый TextChoices с blank

python
from django.db import models

class Priority(models.TextChoices):
    LOW = 'low', 'Низкий'
    MEDIUM = 'medium', 'Средний'
    HIGH = 'high', 'Высокий'

class Task(models.Model):
    title = models.CharField(max_length=200)
    priority = models.CharField(
        max_length=10,
        choices=Priority.choices,
        blank=True,
        null=True
    )

Пример 2: TextChoices с пустым вариантом

python
class Status(models.TextChoices):
    ACTIVE = 'active', 'Активный'
    INACTIVE = 'inactive', 'Неактивный'
    PENDING = 'pending', 'Ожидает'
    __empty__ = 'Статус не указан'

class User(models.Model):
    name = models.CharField(max_length=100)
    status = models.CharField(
        max_length=20,
        choices=Status.choices,
        blank=True
    )

Пример 3: Работа с пустыми значениями в шаблонах

python
# models.py
class Category(models.TextChoices):
    ELECTRONICS = 'electronics', 'Электроника'
    CLOTHING = 'clothing', 'Одежда'
    FOOD = 'food', 'Продукты'
    __empty__ = 'Категория не выбрана'

# views.py
def product_list(request):
    products = Product.objects.all()
    return render(request, 'products/list.html', {'products': products})

# templates/products/list.html
{% for product in products %}
    <p>{{ product.name }} - {{ product.category|default:"Без категории" }}</p>
{% endfor %}

Сравнение с традиционным подходом

Традиционный подход с tuple

python
SEX_CHOICES = (
    ('M', 'Мужской'),
    ('F', 'Женский'),
)

class Person(models.Model):
    sex = models.CharField(max_length=1, choices=SEX_CHOICES, blank=True)

Современный подход с TextChoices

python
class Sex(models.TextChoices):
    MALE = 'M', 'Мужской'
    FEMALE = 'F', 'Женский'
    __empty__ = 'Не указан'

class Person(models.Model):
    sex = models.CharField(max_length=1, choices=Sex.choices, blank=True)

Преимущества TextChoices:

  • Автоматическая генерация констант (Sex.MALE вместо ‘M’)
  • Удобный доступ к меткам (Sex.MALE.label)
  • Поддержка типов (IntegerChoices, TextChoices и др.)
  • Чистый и читаемый код
  • Автоматическое добавление пустого варианта через __empty__

Источники

  1. Django Documentation - Model field reference
  2. Django Forum - models.TextChoices with blank=True
  3. Stack Overflow - How to properly use the “choices” field option in Django
  4. Django Documentation - Models
  5. Reddit - How to organize TextChoices

Заключение

Правильное использование TextChoices в Django требует понимания нескольких ключевых моментов:

  1. Параметр blank должен быть в поле модели, а не в классе выбора
  2. Для добавления пустого варианта используйте атрибут __empty__ в классе выбора
  3. Современный подход с TextChoices предлагает больше преимуществ по сравнению с традиционными tuple choices
  4. Для сохранения NULL в базе данных используйте параметр null=True вместе с blank=True

Следуя этим правилам, вы сможете эффективно использовать TextChoices в своих Django проектах и избежать распространенных ошибок, подобных той, что возникла у вас при попытке передать blank=True напрямую в конструктор класса выбора.

Авторы
Проверено модерацией
Модерация