⚖️ Старый vs Новый подходы

⚡ Главные отличия

  • Enum choices: кастомный Python Enum → встроенный models.TextChoices / IntegerChoices
  • unique_together: устаревший Meta-атрибут → UniqueConstraint в Meta.constraints
  • get_object_or_404: из rest_framework.generics → из rest_framework.generics (не из Django shortcuts в DRF)
  • HTTP 204 vs 200: пустой список → возвращать 200 с [], а не 204

1. Enum choices: кастомный vs встроенный

Из лекции (кастомный Enum)

from enum import Enum

class Statuses(Enum):
    NEW = "NEW"
    IN_PROGRESS = "IN_PROGRESS"
    CLOSED = "CLOSED"

    @classmethod
    def choices(cls):
        return [(attr.name, attr.value)
                for attr in cls]

# В модели:
status = models.CharField(
    max_length=15,
    choices=Statuses.choices,
    default=Statuses.NEW
)

Современный Django 3.0+ TextChoices

from django.db import models

class Statuses(models.TextChoices):
    NEW = "NEW", "Новая"
    IN_PROGRESS = "IN_PROGRESS", "В работе"
    CLOSED = "CLOSED", "Закрыта"

# В модели:
status = models.CharField(
    max_length=15,
    choices=Statuses.choices,
    default=Statuses.NEW
)

Преимущества TextChoices: встроен в Django, автодополнение IDE, метки (verbose names) «из коробки», нет необходимости в методе choices().

⚠️ Проверить по документации: models.TextChoices доступен с Django 3.0. Для целочисленных значений — models.IntegerChoices.

2. unique_together vs UniqueConstraint

Из лекции (устаревший)

class Meta:
    unique_together = ('name', 'project')

Современный Django 2.2+

from django.db.models import UniqueConstraint

class Meta:
    constraints = [
        UniqueConstraint(
            fields=['name', 'project'],
            name='unique_task_per_project'
        )
    ]

unique_together задеприкейтирован в Django 4.2 и будет удалён в будущих версиях. UniqueConstraint даёт именованные ограничения и поддержку условных индексов.

3. HTTP 204 No Content для пустых списков

Из лекции

if not tags.exists():
    return Response(
        data=[],
        status=status.HTTP_204_NO_CONTENT
    )

REST-конвенция (RFC 7231)

# 204 означает «ответ без тела»,
# а не «пустой список»
# Правильно: 200 + пустой массив
return Response(
    data=[],
    status=status.HTTP_200_OK
)

Статус 204 No Content семантически означает «операция выполнена, тело ответа отсутствует» (типично для DELETE). Для GET-запроса с пустым результатом корректнее возвращать 200 OK с пустым массивом [].

4. Плоская структура vs модуль apps/

Стандартная структура Django

myproject/
  tasks/          ← приложение в корне
    models.py
    views.py
  projects/
    models.py
    views.py

Архитектура проекта (из лекции)

myproject/
  apps/           ← модуль-контейнер
    __init__.py
    tasks/
      models/     ← подмодуль моделей
      views/
    projects/
      models/
      views/

Вынесение приложений в модуль apps/ — рекомендуемый паттерн для больших проектов. Позволяет избежать конфликтов имён и упрощает навигацию.