⚖️ Старый vs Новый API

Устаревшие паттерны из лекции → современный Django 5.x + DRF 3.15+

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

  • Enum.choices vs TextChoices: лекция использует самописный Enum — современно через models.TextChoices
  • deleted default=True: в лекции опечатка — логически должно быть default=False
  • date_joined / registered: лекция переименовывает через name="registered" — в Django 5.x это поддерживается, но нестандартно

Из лекции (старое)

# apps/users/choices/positions.py
from enum import Enum

class Positions(Enum):
    CEO = "CEO"
    CTO = "CTO"
    PROGRAMMER = "Programmer"
    ...

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

# В модели:
position = models.CharField(
    max_length=15,
    choices=UserPositions.choices,  # вызов метода
    default=UserPositions.PROGRAMMER
)

Современный подход (Django 5.x)

# apps/users/choices/positions.py
from django.db import models

class UserPositions(models.TextChoices):
    CEO = "CEO", "CEO"
    CTO = "CTO", "CTO"
    PROGRAMMER = "PROGRAMMER", "Programmer"
    DESIGNER = "DESIGNER", "Designer"
    PRODUCT_OWNER = "PRODUCT_OWNER", "Product Owner"
    PROJECT_OWNER = "PROJECT_OWNER", "Project Owner"
    PROJECT_MANAGER = "PROJECT_MANAGER", "Project Manager"
    QA = "QA", "QA"

# В модели:
position = models.CharField(
    max_length=15,
    choices=UserPositions,  # без вызова .choices
    default=UserPositions.PROGRAMMER
)

Почему лучше TextChoices: встроенная поддержка Django ORM (фильтрация, миграции), авто-генерация .choices, .values, .labels. Не нужен метод @classmethod choices().

Из лекции (возможная опечатка)

# В модели User:
deleted = models.BooleanField(default=True)
# Логика: новый пользователь сразу "удалён" —
# это не имеет смысла

Правильно

# В модели User:
deleted = models.BooleanField(default=False)
# Новый пользователь активен (не удалён)
# Soft-delete: при удалении → deleted=True,
# deleted_at=datetime.now()

Из лекции

# Переименование поля через name=
date_joined = models.DateTimeField(
    name="registered", auto_now_add=True
)
# Обращение к полю: user.registered

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

# Явное именование поля
registered = models.DateTimeField(auto_now_add=True)
# или стандартное
date_joined = models.DateTimeField(auto_now_add=True)
# Подход через name= работает, но нестандартен
# и путает при миграциях

Из лекции (опечатка в Meta)

# apps/tasks/serializers
class CreateUpdateTaskSerializer(serializers.ModelSerializer):
    ...
    class Meta:
       model = Task
       fields = (
          'deadline',
          'Assignee'  # опечатка — с большой буквы
       )

Правильно

class CreateUpdateTaskSerializer(serializers.ModelSerializer):
    assignee = serializers.SlugRelatedField(
        slug_field='email',
        queryset=User.objects.all(),
        required=False
    )
    class Meta:
       model = Task
       fields = (
          'deadline',
          'assignee',   # строчная
          # ... другие нужные поля
       )