← Назад к вопросам

Для чего нужен IntegerChoices?

2.3 Middle🔥 161 комментариев
#Django

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

IntegerChoices в Django: назначение и применение

IntegerChoices — это специальный класс Django, который позволяет определять наборы целочисленных константных значений с понятными метками. Это более типизированная и безопасная альтернатива кортежам для определения выбора в моделях Django.

1. Основное назначение и синтаксис

Используется при определении полей с ограниченным набором значений:

from django.db import models

class Order(models.Model):
    class Status(models.IntegerChoices):
        PENDING = 1, "В ожидании"
        PROCESSING = 2, "В обработке"
        COMPLETED = 3, "Завершён"
        CANCELLED = 4, "Отменён"
    
    status = models.IntegerField(
        choices=Status.choices,
        default=Status.PENDING
    )

# Использование
order = Order.objects.create(status=Order.Status.PENDING)
print(order.status)  # 1 (целое число в БД)
print(order.get_status_display())  # "В ожидании"

Ключевое отличие от старого подхода — типизация и читаемость.

2. Преимущества перед кортежами

Старый подход с кортежами:

# ❌ Старый способ — ненадёжно
STATUS_CHOICES = (
    (1, "В ожидании"),
    (2, "В обработке"),
    (3, "Завершён"),
)

status = models.IntegerField(choices=STATUS_CHOICES, default=1)

# Проблемы:
# - Магические числа в коде (1, 2, 3)
# - Нет автодополнения в IDE
# - Легко ошибиться с номером

Новый подход с IntegerChoices:

# ✅ Новый способ — типизировано и безопасно
class Status(models.IntegerChoices):
    PENDING = 1, "В ожидании"
    PROCESSING = 2, "В обработке"

status = models.IntegerField(choices=Status.choices)

# Преимущества:
# - Легко обращаться: Status.PENDING (1)
# - IDE знает о всех значениях
# - Самодокументирующийся код
# - Type hints работают правильно

3. Работа в кодовой базе

На практике IntegerChoices существенно улучшают код:

from django.db import models

class Payment(models.Model):
    class Method(models.IntegerChoices):
        CREDIT_CARD = 1, "Кредитная карта"
        PAYPAL = 2, "PayPal"
        BANK_TRANSFER = 3, "Банковский перевод"
        CRYPTO = 4, "Криптовалюта"
    
    class Status(models.IntegerChoices):
        NEW = 1, "Новая"
        PROCESSING = 2, "В обработке"
        SUCCESS = 3, "Успешна"
        FAILED = 4, "Ошибка"
        REFUNDED = 5, "Возвращена"
    
    method = models.IntegerField(choices=Method.choices)
    status = models.IntegerField(choices=Status.choices, default=Status.NEW)
    amount = models.DecimalField(max_digits=10, decimal_places=2)

# В сервисах и контроллерах
def process_payment(payment: Payment) -> bool:
    if payment.method == Payment.Method.CREDIT_CARD:
        return process_card_payment(payment)
    elif payment.method == Payment.Method.PAYPAL:
        return process_paypal(payment)
    # IDE автодополнит все возможные значения

4. Использование в запросах и логике

Удобство в фильтрации и обновлении:

# Вместо magic numbers
orders = Order.objects.filter(status=Order.Status.COMPLETED)

# Обновление с типизацией
Order.objects.filter(id=order_id).update(
    status=Order.Status.PROCESSING
)

# В условиях
def send_completion_email(order):
    if order.status == Order.Status.COMPLETED:
        send_email(order.user)

5. Интеграция с API и сериализаторами

В REST API работает гладко:

from rest_framework import serializers

class PaymentSerializer(serializers.ModelSerializer):
    method_display = serializers.CharField(
        source="get_method_display",
        read_only=True
    )
    status_display = serializers.CharField(
        source="get_status_display",
        read_only=True
    )
    
    class Meta:
        model = Payment
        fields = [
            'id', 'method', 'method_display',
            'status', 'status_display', 'amount'
        ]

# API вернёт:
# {
#   "method": 1,
#   "method_display": "Кредитная карта",
#   "status": 3,
#   "status_display": "Успешна"
# }

6. Валидация и тестирование

Облегчает проверку корректности:

class PaymentSerializer(serializers.ModelSerializer):
    method = serializers.IntegerField(
        min_value=Payment.Method.CREDIT_CARD,
        max_value=Payment.Method.CRYPTO
    )
    
    def validate_method(self, value):
        valid_methods = list(Payment.Method.values)
        if value not in valid_methods:
            raise serializers.ValidationError(
                f"Invalid method. Must be one of {valid_methods}"
            )
        return value

# Тестирование
def test_payment_creation():
    payment = Payment.objects.create(
        method=Payment.Method.CREDIT_CARD,
        status=Payment.Status.NEW,
        amount=100.00
    )
    assert payment.method == Payment.Method.CREDIT_CARD
    assert payment.get_method_display() == "Кредитная карта"

7. Вспомогательные методы

IntegerChoices предоставляет удобные методы:

class Status(models.IntegerChoices):
    ACTIVE = 1, "Активный"
    INACTIVE = 0, "Неактивный"

# Получить все значения
print(Status.values)        # [1, 0]

# Получить все метки
print(Status.labels)        # ["Активный", "Неактивный"]

# Получить все пары
print(Status.choices)       # [(1, "Активный"), (0, "Неактивный")]

# Перебор
for status in Status:
    print(f"{status.name} = {status.value}")

Ключевые практики:

  • Всегда используй IntegerChoices вместо кортежей в новых проектах
  • Группируй связанные choices в одном классе
  • Добавляй русские метки для пользовательского интерфейса
  • Тестируй все значения choices в unit тестах
  • Документируй нестандартные значения в комментариях

IntegerChoices — это простой, но мощный инструмент, который делает Django код типизированным, безопасным и поддерживаемым.

Для чего нужен IntegerChoices? | PrepBro