📝 Задания мини-проекта Agile Projects

9 задач: модели (1–4) · теги API (5–6) · проекты API (7–8) · файлы API (9)

⚡ Все задачи — кратко

  1. Задание 1: Модуль apps/, приложение tasks, модель Tag (name, MinLengthValidator(4)), миграции, коммит
  2. Задание 2: Приложение projects, модель Project (name unique, description, created_at, Meta ordering), миграции, коммит
  3. Задание 3: Модель ProjectFile (file_name, file_path, created_at), связь M2M Project ↔ ProjectFile, @property count_of_files, миграции
  4. Задание 4: Модель Task (все поля: FK к Project и User, M2M к Tag, Enum Statuses/Priority, deadline=конец_месяца, unique_together), миграции
  5. Задание 5: TagSerializer, TagListAPIView (GET список + POST создание), URL /api/v1/tags/
  6. Задание 6: TagDetailAPIView (GET/PUT/DELETE по pk), URL /api/v1/tags/<pk>/
  7. Задание 7: AllProjectsSerializer + CreateProjectSerializer (валидация description ≥ 30 символов), ProjectsListAPIView (GET с фильтром дат + POST), URL /api/v1/projects/
  8. Задание 8: ProjectDetailSerializer, ProjectDetailAPIView (GET/PUT с partial=True/DELETE), URL /api/v1/projects/<pk>/
  9. Задание 9: upload_file_helpers (check_extension, check_file_size, create_file_path, save_file), сериализаторы файлов, ProjectFileListAPIView (GET + POST), URL /api/v1/projects/files/
Контекст: Вы — Python-разработчик в крупной компании и получили новый проект от клиента — «Agile Projects». Этот проект — будущая веб-платформа для управления проектами, задачами и сотрудниками, ориентированной на использование в рамках Agile-методологии. Платформа реализуется на Django + DRF с REST API.

Задание 1 — Создание приложений, регистрация первой модели Tag

  1. Для большего контроля и чистоты архитектуры создайте модуль apps, переместите только что созданное приложение в этот модуль.
  2. Создайте первое приложение tasks.
  3. Зарегистрируйте новое приложение в настройках Django.
  4. Создайте модуль models в приложении tasks и создайте первую модель Tag в файле tag.py:
    • name (строковое поле, максимальная длина 20, минимальная длина — 4)
    • Строковое отображение объекта должно быть в виде его имени (магический метод __str__)
  5. Проведите миграции, убедитесь, что всё работает, запустив сервер.
  6. Зафиксируйте все изменения, сделайте запрос на слияние.

Посмотреть решение

Задание 2 — Второе приложение и модель Project

  1. Создайте приложение projects.
  2. Зарегистрируйте новое приложение в настройках Django.
  3. Создайте модуль models в приложении projects и создайте первую модель Project в файле project.py:
    • name (строковое поле, максимальная длина 100, уникальное)
    • description (большое строковое поле, обязательно к заполнению)
    • created_at — поле даты и времени, заполняется автоматически при создании проекта
    • Строковое отображение объекта должно быть в виде его имени (__str__)
    • Определение класса Meta для сортировки проектов по их имени
  4. Проведите миграции, убедитесь, что всё работает, запустив сервер.
  5. Зафиксируйте все изменения, сделайте запрос на слияние.

Посмотреть решение

Задание 3 — Модель файлов, построение связи с проектами

  1. В приложении projects создайте новую модель ProjectFile:
    • file_name — строковое поле, максимальная длина 120 символов
    • file_path — поле загрузки файлов, таргет сохранения — папка documents
    • created_at — дата создания файла, автозаполняется при создании нового файла
    • Отображение объектов по полю file_name (магический метод __str__)
    • Сортировка записей по дате создания в порядке убывания
  2. В модели Project создайте новое поле files, которое будет связывать проекты и файлы связью «Многие ко Многим», связующее поле — project.
  3. В модели Project добавьте динамическое поле count_of_files через декоратор @property, которое будет высчитывать количество файлов для проекта.
  4. Проведите миграции, убедитесь, что всё работает, запустив сервер.
  5. Зафиксируйте все изменения, сделайте запрос на слияние.

Посмотреть решение

Задание 4 — Модель Задач, связь с проектами и пользователями

  1. В приложении tasks создайте новую модель Task:
    • name — строковое поле, максимальное значение 120 символов
    • description — большое строковое поле, обязательно к заполнению
    • status — строковое поле, max 15 символов, выбор из Enum класса Statuses, значение по умолчанию — NEW
    • priority — цифровое маленькое поле, выбор из Enum класса Priority, значение по умолчанию — MEDIUM
    • project — ForeignKey к модели Project, при удалении проекта все задачи удаляются, related_name — tasks
    • tags — ManyToMany к модели Tag, related_name — tasks
    • created_at — дата и время, автозаполнение при создании
    • updated_at — дата и время, автозаполнение при создании и обновлении
    • deleted_at — дата и время, может быть пустым
    • deadline — дата и время, обязательно. По умолчанию — расчёт последнего дня текущего месяца при создании
    • assignee — ForeignKey к модели User от Django, защита от удаления, related_name — tasks, может отсутствовать
  2. Добавьте строковое отображение задач в формате: «название задачи, статус».
  3. Добавьте сортировку по дедлайн-дате в порядке убывания.
  4. Добавьте уникальность по полям name и project.
  5. Проведите миграции, убедитесь, что всё работает, запустив сервер.
  6. Зафиксируйте все изменения, сделайте запрос на слияние.

Посмотреть решение

Задание 5 — Получение списка всех тегов и создание нового тега

  1. В приложении tasks удалите файл views.py, создайте модуль views.
  2. В модуле views создайте новый файл tag_views.py.
  3. В приложении tasks создайте новый модуль serializers.
  4. В модуле serializers создайте новый файл tag_serializers.py.
  5. Напишите сериализатор для работы с тегами (так как у нас всего одно поле в этой модели, сериализатор будет один на все будущие запросы).
  6. Напишите классовое отображение:
    • Реализовать метод для получения всех объектов Tag
    • Для получения списка всех тегов методом get
    • Для создания нового тега методом post
  7. Зарегистрируйте новое классовое отображение в списке эндпоинтов.
  8. Проверьте работу нашего классового отображения.
  9. Зафиксируйте все изменения, сделайте запрос на слияние.

Посмотреть решение

Задание 6 — Получение, обновление и удаление тега

  1. В файле tag_views.py создайте новый класс TagDetailAPIView.
  2. Напишите отдельный метод, который позволит получать конкретный объект по его id.
  3. Реализуйте метод get для получения конкретного тега.
  4. Реализуйте метод put для возможности обновления информации о теге (обновление поля name).
  5. Реализуйте метод delete для возможности удалить конкретный тег по его id.
  6. Проверьте работу нашего классового отображения.
  7. Зафиксируйте все изменения, сделайте запрос на слияние.

Посмотреть решение

Задание 7 — Получение списка проектов и создание нового проекта

  1. В приложении projects создайте модули serializers, views, удалите файл views.py.
  2. В модуле serializers создайте файл project_serializers.py.
  3. Создайте первый сериализатор AllProjectsSerializer на получение информации о всех проектах. Отображаемые поля: id, name, created_at.
  4. В модуле views создайте файл project_views.py, напишите классовое отображение:
    • Реализуйте метод на получение списка всех проектов:
      1. Получить из query_params значения дат date_from, date_to
      2. Если никаких значений передано не было — получить список полностью всех проектов
      3. Если были переданы значения для временного диапазона — сконвертировать полученные значения по текущей временной зоне (поможет метод make_aware() и модуль timezone в Django)
      4. Провести фильтрацию по диапазону дат date_fromdate_to
    • Реализуйте метод get на отображение списка всех проектов, добавьте фильтрацию через query_params на получение проектов в определённом временном промежутке
    • Реализуйте метод на создание нового проекта
  5. Зарегистрируйте новое отображение в файле urls.py в приложении projects.
  6. Проверьте работу нашего классового отображения.
  7. Зафиксируйте все изменения, сделайте запрос на слияние.

Посмотреть решение

Задание 8 — Получение, обновление и удаление проекта

  1. Создайте новый сериализатор ProjectDetailSerializer для получения конкретной информации по проекту:
    • name
    • description
    • created_at
    • count_of_files
  2. Напишите новый класс-отображение ProjectDetailAPIView для получения конкретного проекта, обновления и удаления проекта.
    • При обновлении полученного проекта добавьте возможность частичного обновления полей.
  3. Зарегистрируйте новый эндпоинт, проверьте как отрабатывают запросы GET, PUT, DELETE.
  4. Зафиксируйте все изменения, сделайте запрос на слияние.

Посмотреть решение

Задание 9 — Работа с файлами

  1. В приложении projects создайте новый модуль utils.
  2. Создайте в этом модуле файл upload_file_helpers.py.
  3. В этом файле необходимо создать функции:
    • Функция на проверку валидных расширений файла
    • Функция на проверку размерности файла (файл не должен быть больше 2 MB)
    • Функция на создание пути для сохранения файла
    • Функция на сохранение файла (файл должен записываться по частям для избежания потенциальных ошибок и потери данных)
  4. В модуле serializers в приложении projects создайте новый файл project_file_serializers.py.
  5. Создайте сериализатор AllProjectFilesSerializer для отображения краткой информации по всем файлам: id, file_name, project.
  6. Создайте сериализатор CreateProjectFileSerializer для создания нового файла:
    • Для создания необходимо только поле file_name
    • Поле file_name необходимо валидировать:
      1. Проверка на наличие символов из таблицы ASCII
      2. Проверка на доступные расширения файлов (pdf, csv, doc, xlsx)
  7. Переопределите метод create:
    • Перед сохранением файла необходимо создать путь для сохранения
    • Также необходимо получить из тела запроса сам файл и проверить его на размерность (не более 2 MB)
    • Если файл проходит все проверки — сохранить его в проекте, сохранить объект файла
    • Если файл слишком большой — поднять исключение валидации с сообщением об ошибке
  8. Напишите класс-отображение ProjectFileListAPIView для получения списка всех файлов:
    • Реализовать метод на получение всех файлов для конкретного проекта по имени проекта. Если имя проекта не было передано — выводить список полностью всех файлов.
  9. Добавьте в класс-отображение ProjectFileListAPIView метод post для создания нового файла и привязки его к конкретному проекту (проект получать через поле id, которое будет передаваться в теле запроса).
  10. Зарегистрируйте новый эндпоинт, проверьте как отрабатывают запросы GET, POST.
  11. Зафиксируйте все изменения, сделайте запрос на слияние.

Посмотреть решение