🏠 Домашнее задание 15 — Урок 33
⚡ Суть ДЗ 15
Два задания на замену FBV/классов представлений на Generic Views + фильтрацию/поиск/сортировку в проекте «Менеджер задач»:
- Задание 1: Tasks — ListCreateAPIView + RetrieveUpdateDestroyAPIView + фильтрация по status/deadline, поиск по title/description, сортировка по created_at
- Задание 2: SubTasks — то же самое для подзадач
- Агрегирующий эндпойнт статистики — оставить как есть
- Сдать: ссылку на git + скриншоты из Postman
📋 Текст задания (из LMS)
Используя Generic Views, замените существующие классы представлений для задач (Tasks) и подзадач (SubTasks) на соответствующие классы для полного CRUD (Create, Read, Update, Delete) функционала. Агрегирующий эндпойнт для статистики задач оставьте как есть. Реализуйте фильтрацию, поиск и сортировку для этих наборов представлений.
Задание 1: Замена представлений для задач (Tasks) на Generic Views
Шаги для выполнения:
-
Замените классы представлений для задач на Generic Views:
- Используйте
ListCreateAPIViewдля создания и получения списка задач. - Используйте
RetrieveUpdateDestroyAPIViewдля получения, обновления и удаления задач.
- Используйте
-
Реализуйте фильтрацию, поиск и сортировку:
- Реализуйте фильтрацию по полям
statusиdeadline. - Реализуйте поиск по полям
titleиdescription. - Добавьте сортировку по полю
created_at.
- Реализуйте фильтрацию по полям
Задание 2: Замена представлений для подзадач (SubTasks) на Generic Views
-
Замените классы представлений для подзадач на Generic Views:
- Используйте
ListCreateAPIViewдля создания и получения списка подзадач. - Используйте
RetrieveUpdateDestroyAPIViewдля получения, обновления и удаления подзадач.
- Используйте
-
Реализуйте фильтрацию, поиск и сортировку:
- Реализуйте фильтрацию по полям
statusиdeadline. - Реализуйте поиск по полям
titleиdescription. - Добавьте сортировку по полю
created_at.
- Реализуйте фильтрацию по полям
Оформление ответа
- Предоставьте решение: прикрепите ссылку на git.
- Скриншоты тестирования: приложите скриншоты из браузера или Postman, подтверждающие успешное создание, обновление, получение и удаление данных через API.
🔧 Подготовка окружения
Структура проекта (предполагаем, что проект уже существует)
task_manager/
├── manage.py
├── task_manager/
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── tasks/
├── models.py
├── serializers.py
├── views.py
└── urls.py
1. Активация виртуального окружения
# Windows PowerShell
cd task_manager
.\.venv\Scripts\Activate.ps1
# Проверка
python -m pip list | Select-String "djangorestframework"
2. Установка django-filter (если не установлен)
pip install django-filter
pip freeze > requirements.txt
3. Добавление в settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'django_filters', # ← добавить
'tasks',
]
4. Проверка моделей Task и SubTask
Убедитесь, что в tasks/models.py есть поля status, deadline, title, description, created_at. Примерная структура:
# tasks/models.py
from django.db import models
class Task(models.Model):
STATUS_CHOICES = [
('New', 'New'),
('In progress', 'In progress'),
('Done', 'Done'),
]
title = models.CharField(max_length=200)
description = models.TextField(blank=True)
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='New')
deadline = models.DateTimeField(null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
class SubTask(models.Model):
STATUS_CHOICES = [
('New', 'New'),
('In progress', 'In progress'),
('Done', 'Done'),
]
title = models.CharField(max_length=200)
description = models.TextField(blank=True)
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='New')
deadline = models.DateTimeField(null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
task = models.ForeignKey(Task, on_delete=models.CASCADE,
related_name='subtasks')
def __str__(self):
return self.title
Если структура изменялась — создайте и примените миграции:
python manage.py makemigrations
python manage.py migrate
💡 Пошаговое решение
Шаг 1: Обновить сериализаторы (если нужно)
Убедитесь, что сериализаторы покрывают все нужные поля. Если их ещё нет — создайте:
# tasks/serializers.py
from rest_framework import serializers
from .models import Task, SubTask
class TaskSerializer(serializers.ModelSerializer):
class Meta:
model = Task
fields = ['id', 'title', 'description', 'status', 'deadline', 'created_at']
read_only_fields = ['created_at']
class SubTaskSerializer(serializers.ModelSerializer):
class Meta:
model = SubTask
fields = ['id', 'title', 'description', 'status', 'deadline',
'created_at', 'task']
read_only_fields = ['created_at']
Связь с теорией: см. Часть 4 теории — filter_backends.
Шаг 2: Заменить представления Tasks на Generic Views
# tasks/views.py
from rest_framework.generics import (
ListCreateAPIView,
RetrieveUpdateDestroyAPIView,
)
from rest_framework import filters
from django_filters.rest_framework import DjangoFilterBackend
from .models import Task, SubTask
from .serializers import TaskSerializer, SubTaskSerializer
# ────── Tasks ──────
class TaskListCreateView(ListCreateAPIView):
"""
GET /tasks/ — список задач (с фильтрацией/поиском/сортировкой)
POST /tasks/ — создание задачи
"""
queryset = Task.objects.all()
serializer_class = TaskSerializer
filter_backends = [
DjangoFilterBackend, # ?status=New, ?deadline=2025-12-31
filters.SearchFilter, # ?search=текст
filters.OrderingFilter, # ?ordering=created_at или ?ordering=-created_at
]
filterset_fields = ['status', 'deadline']
search_fields = ['title', 'description']
ordering_fields = ['created_at']
class TaskDetailUpdateDeleteView(RetrieveUpdateDestroyAPIView):
"""
GET /tasks/<pk>/ — получение задачи
PUT /tasks/<pk>/ — полное обновление
PATCH /tasks/<pk>/ — частичное обновление
DELETE /tasks/<pk>/ — удаление
"""
queryset = Task.objects.all()
serializer_class = TaskSerializer
# ────── SubTasks ──────
class SubTaskListCreateView(ListCreateAPIView):
"""
GET /subtasks/ — список подзадач
POST /subtasks/ — создание подзадачи
"""
queryset = SubTask.objects.all()
serializer_class = SubTaskSerializer
filter_backends = [
DjangoFilterBackend,
filters.SearchFilter,
filters.OrderingFilter,
]
filterset_fields = ['status', 'deadline']
search_fields = ['title', 'description']
ordering_fields = ['created_at']
class SubTaskDetailUpdateDeleteView(RetrieveUpdateDestroyAPIView):
"""
GET /subtasks/<pk>/ — получение подзадачи
PUT /subtasks/<pk>/ — полное обновление
PATCH /subtasks/<pk>/ — частичное обновление
DELETE /subtasks/<pk>/ — удаление
"""
queryset = SubTask.objects.all()
serializer_class = SubTaskSerializer
Шаг 3: Обновить URL-маршруты
# tasks/urls.py
from django.urls import path
from .views import (
TaskListCreateView,
TaskDetailUpdateDeleteView,
SubTaskListCreateView,
SubTaskDetailUpdateDeleteView,
# Агрегирующий эндпойнт статистики оставляем как есть:
# TaskStatsView,
)
urlpatterns = [
# Tasks
path('tasks/', TaskListCreateView.as_view(), name='task-list-create'),
path('tasks/<int:pk>/', TaskDetailUpdateDeleteView.as_view(),
name='task-detail-update-delete'),
# SubTasks
path('subtasks/', SubTaskListCreateView.as_view(),
name='subtask-list-create'),
path('subtasks/<int:pk>/', SubTaskDetailUpdateDeleteView.as_view(),
name='subtask-detail-update-delete'),
# Агрегирующий эндпойнт (не трогаем)
# path('tasks/stats/', TaskStatsView.as_view(), name='task-stats'),
]
Шаг 4: Запустить сервер и проверить
python manage.py runserver
Открыть в браузере DRF Browsable API:
http://127.0.0.1:8000/tasks/— список задачhttp://127.0.0.1:8000/subtasks/— список подзадач
🔬 Проверка в Postman
Связь с теорией: см. Пример 4 — filter_backends.
Создание задачи (POST)
POST http://127.0.0.1:8000/tasks/
Content-Type: application/json
{
"title": "Изучить DRF фильтрацию",
"description": "Изучить filter_backends, search_fields, ordering_fields",
"status": "New",
"deadline": "2025-12-31T23:59:00Z"
}
Ожидаемый ответ: 201 Created
{
"id": 1,
"title": "Изучить DRF фильтрацию",
"description": "...",
"status": "New",
"deadline": "2025-12-31T23:59:00Z",
"created_at": "2025-06-09T10:00:00Z"
}
Получение списка (GET)
GET http://127.0.0.1:8000/tasks/
Ожидаемый ответ: 200 OK — массив всех задач
Фильтрация по статусу
GET http://127.0.0.1:8000/tasks/?status=New
Ожидаемый ответ: только задачи со статусом "New"
Поиск по тексту
GET http://127.0.0.1:8000/tasks/?search=DRF
Ожидаемый ответ: задачи, где title или description содержит "DRF"
Сортировка по дате создания
# По убыванию (новые сначала)
GET http://127.0.0.1:8000/tasks/?ordering=-created_at
# По возрастанию (старые сначала)
GET http://127.0.0.1:8000/tasks/?ordering=created_at
Получение конкретной задачи (GET)
GET http://127.0.0.1:8000/tasks/1/
Ожидаемый ответ: 200 OK — объект задачи
Частичное обновление (PATCH)
PATCH http://127.0.0.1:8000/tasks/1/
Content-Type: application/json
{"status": "In progress"}
Ожидаемый ответ: 200 OK — обновлённый объект
Удаление (DELETE)
DELETE http://127.0.0.1:8000/tasks/1/
Ожидаемый ответ: 204 No Content
Те же тесты повторить для SubTasks
Замените /tasks/ на /subtasks/ во всех запросах выше.
💻 Отладка в VS Code
Запуск через терминал
# В терминале VS Code (Ctrl+`)
.\.venv\Scripts\Activate.ps1
python manage.py runserver
Запуск через F5 (launch.json)
Создайте файл .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"name": "Django: runserver",
"type": "debugpy",
"request": "launch",
"program": "${workspaceFolder}/manage.py",
"args": ["runserver"],
"django": true,
"justMyCode": true
}
]
}
Нажмите F5 — сервер запустится с поддержкой отладки.
Точки останова
Для отладки filter_backends поставьте точку останова в методе get_queryset() или в методе filter_queryset():
- Откройте
tasks/views.py - Кликните слева от номера строки в методе класса (например, на строке
queryset = Task.objects.all()) - Нажмите F5 и отправьте запрос из Postman
- VS Code остановится на точке — можно просмотреть
self.request.query_paramsв панели Variables
Проверка установки пакетов
# В терминале VS Code
pip show django-filter
# Должно показать версию и расположение пакета
📤 Оформление ответа
1. Коммит в git
# Добавить изменения
git add tasks/views.py tasks/urls.py tasks/serializers.py requirements.txt
# Коммит
git commit -m "feat: замена FBV на Generic Views для Tasks и SubTasks (ДЗ 15)
- TaskListCreateView и TaskDetailUpdateDeleteView с filter_backends
- SubTaskListCreateView и SubTaskDetailUpdateDeleteView с filter_backends
- Фильтрация по status, deadline; поиск по title, description; сортировка по created_at
"
# Пуш на GitHub
git push origin main
2. Скриншоты для сдачи
Сделайте скриншоты из Postman, подтверждающие:
- POST /tasks/ — успешное создание (код 201)
- GET /tasks/ — список задач
- GET /tasks/?status=New — фильтрация
- GET /tasks/?search=... — поиск
- GET /tasks/?ordering=-created_at — сортировка
- PATCH /tasks/1/ — обновление (код 200)
- DELETE /tasks/1/ — удаление (код 204)
- Те же операции для SubTasks