🐛 Типичные ошибки

⚡ Топ-5 ошибок

  1. Неправильный путь в INSTALLED_APPS: 'tasks' вместо 'apps.tasks.apps.TasksConfig'
  2. Нет __init__.py в модуле models/: Django не видит классы моделей
  3. Забыт make_aware(): сравнение naive datetime с aware → RuntimeWarning / TypeError
  4. Enum choices вызывается без скобок: choices=Statuses.choices (правильно) vs choices=Statuses.choices() (ошибка при передаче)
  5. Файл через request.data вместо request.FILES: файл не будет доступен

1. Неверный путь регистрации приложения в INSTALLED_APPS

Проблема: Приложение не найдено Django или миграции не создаются.

# НЕПРАВИЛЬНО — просто имя
INSTALLED_APPS = ['tasks', 'projects']

# ПРАВИЛЬНО — полный путь с AppConfig
INSTALLED_APPS = [
    'apps.tasks.apps.TasksConfig',
    'apps.projects.apps.ProjectsConfig',
]

Почему: При использовании модуля apps/ Django должен знать полный путь к классу конфигурации приложения.

2. Отсутствие __init__.py в модуле models/

Проблема: ImportError: cannot import name 'Tag' from 'apps.tasks.models'

# НЕПРАВИЛЬНО — нет экспорта
# apps/tasks/models/__init__.py пустой

# ПРАВИЛЬНО — явный экспорт классов
# apps/tasks/models/__init__.py
from apps.tasks.models.tag import Tag
from apps.tasks.models.task import Task

Аналогично для apps/projects/models/__init__.py.

3. Naive datetime при фильтрации по датам

Проблема: RuntimeWarning: DateTimeField received a naive datetime или TypeError: can't compare offset-naive and offset-aware datetimes

# НЕПРАВИЛЬНО
date_from = datetime.strptime(date_from, '%Y-%m-%d')
# Объект без timezone (naive)

# ПРАВИЛЬНО
from django.utils import timezone
date_from = timezone.make_aware(
    datetime.strptime(date_from, '%Y-%m-%d')
)
# Объект с timezone (aware)

Django хранит DateTimeField с учётом USE_TZ = True. Все сравнения должны быть между aware datetime.

4. Неверное обращение к Enum choices в модели

Проблема: Поле принимает неожиданные значения или выдаёт ошибку при миграции.

# НЕПРАВИЛЬНО — choices передаётся как результат вызова
status = models.CharField(
    choices=Statuses.choices(),   # вернёт список, не callable
    default=Statuses.NEW          # это Enum-объект, не строка
)

# ПРАВИЛЬНО — ссылка на classmethod без вызова
status = models.CharField(
    max_length=15,
    choices=Statuses.choices,     # передаём ссылку на classmethod
    default=Statuses.NEW          # Django вызовет .value автоматически
)

5. Файл через request.data вместо request.FILES

Проблема: KeyError: 'file' или файл получается как строка вместо InMemoryUploadedFile.

# НЕПРАВИЛЬНО
file_content = request.data["file"]

# ПРАВИЛЬНО
file_content = request.FILES["file"]
# Для текстовых полей — request.data
project_id = request.data["project_id"]

Файлы при multipart/form-data попадают в request.FILES, а текстовые поля — в request.data.

6. Создание приложения не в папке apps/

Проблема: Приложение создаётся в корне проекта вместо модуля apps/.

# НЕПРАВИЛЬНО — запуск из корня проекта
python manage.py startapp tasks
# Создаст apps/tasks в корне, а не в apps/

# ПРАВИЛЬНО — запуск из папки apps/
cd apps
python ../manage.py startapp tasks
# Создаст apps/tasks

7. Отсутствие content_type multipart в POST-запросе загрузки файла

Проблема: Файл не загружается, request.FILES пустой.

# Postman: при загрузке файла выбрать Body → form-data
# и установить тип поля 'file' как 'File', а не 'Text'

# curl-аналог:
curl -X POST http://localhost:8000/api/v1/projects/files/ \
  -F "file_name=report.pdf" \
  -F "project_id=1" \
  -F "file=@/path/to/report.pdf"