⚖️ Старый vs Новый: паттерны из лекции

К оглавлению урока

Этот раздел показывает устаревшие или упрощённые паттерны из лекции и их современные аналоги. Используй актуальный код в своих проектах.

⚡ Основные различия

  • Валидаторы в Meta (лекция) → валидаторы на уровне класса (современно)
  • create_file_path с split('.') → безопаснее rsplit('.', 1)
  • Опечатка CreateTasSerializerCreateTaskSerializer
  • deleted по умолчанию True → логичнее False (удалён=False по умолчанию)
  • validate_deadline без is_naive → в DRF 3.15+ datetime уже aware

1. Методы validate_ внутри class Meta (из лекции — неработающий код)

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

class CreateTaskSerializer(serializers.ModelSerializer):
    class Meta:
        model = Task
        fields = (...)

        # ❌ Внутри Meta — DRF игнорирует!
        def validate_name(self, value):
            if len(value) < 10:
                raise serializers.ValidationError(...)
            return value

Современный (DRF 3.15+)

class CreateTaskSerializer(serializers.ModelSerializer):
    class Meta:
        model = Task
        fields = (...)

    # ✅ На уровне класса сериализатора
    def validate_name(self, value: str) -> str:
        if len(value) < 10:
            raise serializers.ValidationError(
                "Too short — min 10 characters"
            )
        return value

2. Функция create_file_path с split('.') (из лекции — потенциальная ошибка)

Из лекции

def create_file_path(project_name, file_name):
    # ❌ split('.') сломается если в имени
    # несколько точек: "my.report.pdf"
    new_file_name, file_ext = file_name.split('.')
    file_path = "documents/{}/{}.{}".format(
        project_name.replace(' ', '_'),
        new_file_name.replace(' ', '_'),
        file_ext
    )
    return file_path

Современный

def create_file_path(project_name: str, file_name: str) -> str:
    # ✅ rsplit с maxsplit=1 — безопасно
    stem, ext = file_name.rsplit('.', 1)
    file_path = "documents/{}/{}.{}".format(
        project_name.replace(' ', '_'),
        stem.replace(' ', '_'),
        ext
    )
    return file_path

3. Опечатка в имени класса (из лекции — баг)

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

def post(self, request, *args, **kwargs):
    # ❌ Опечатка: CreateTasSerializer
    serializer = CreateTasSerializer(data=request.data)
    ...

Правильно

def post(self, request, *args, **kwargs):
    # ✅ CreateTaskSerializer (с k)
    serializer = CreateTaskSerializer(data=request.data)
    ...

4. Поле deleted по умолчанию True (из лекции — логическая ошибка)

Из лекции

class User(AbstractBaseUser, PermissionsMixin):
    # ❌ default=True означает "удалён по умолчанию"
    deleted = models.BooleanField(default=True)

Логически правильно

class User(AbstractBaseUser, PermissionsMixin):
    # ✅ default=False — пользователь не удалён
    deleted = models.BooleanField(default=False)

5. validate_deadline без проверки aware/naive

Из лекции

def validate_deadline(self, value: str) -> int:
    # Применяет make_aware всегда —
    # в DRF 3.15+ значение уже aware
    value = timezone.make_aware(
        value, timezone.get_current_timezone()
    )
    if value < timezone.now():
        raise serializers.ValidationError(...)
    return value

DRF 3.15+

def validate_deadline(self, value) -> ...:
    # Проверяем is_naive перед make_aware
    if timezone.is_naive(value):
        value = timezone.make_aware(
            value, timezone.get_current_timezone()
        )
    if value < timezone.now():
        raise serializers.ValidationError(
            "The deadline cannot be in the past"
        )
    return value

6. ProjectFileListAPIView vs ProjectFileListGenericView (расхождение имён)

В лекции есть расхождение: в одном месте класс называется ProjectFileListAPIView, в другом — ProjectFileListGenericView. В urls.py регистрируется ProjectFileListGenericView (GenericView). Придерживайся единого имени в своём коде.

Вывод: При написании кода по этой лекции — всегда переносить методы validate_* на уровень класса, исправлять опечатки и проверять is_naive() перед make_aware().