🏠 Домашнее задание 8: Менеджер задач

📁 Из LMS: Python Advanced — Домашнее задание 8

⚡ Задание (из LMS)

Проект «Менеджер задач». Создать структуру и зарегистрировать модели в Admin.

Модели:

  • Category: name
  • Task: title (unique_for_date), description, categories (M2M), status (choices), deadline, created_at (auto)
  • SubTask: title, description, task (ForeignKey), status (choices), deadline, created_at (auto)

Статусы: New, In progress, Pending, Blocked, Done

Шаги: модели → makemigrations → migrate → admin.py → createsuperuser → создать объекты → скриншоты → git commit → push → ссылка в LMS

Текст задания из LMS

Python Advanced: Домашнее задание 8
Источник: lms.itcareerhub.de — Python Adv 15: Модели Django

Проект «Менеджер задач»

Цель: Создать структуру менеджера задач и зарегистрировать модели в панели администратора Django.

Реализовать модели:

Модель Task

Описание: Задача для выполнения.

Поля:

  • title — Название задачи. Уникально для даты (unique_for_date).
  • description — Описание задачи.
  • categories — Категории задачи. Многие ко многим.
  • status — Статус задачи. Выбор из: New, In progress, Pending, Blocked, Done.
  • deadline — Дата и время дедлайна.
  • created_at — Дата и время создания. Автоматическое заполнение.

Модель SubTask

Описание: Отдельная часть основной задачи (Task).

Поля:

  • title — Название подзадачи.
  • description — Описание подзадачи.
  • task — Основная задача. Один ко многим (ForeignKey).
  • status — Статус задачи. Выбор из: New, In progress, Pending, Blocked, Done.
  • deadline — Дата и время дедлайна.
  • created_at — Дата и время создания. Автоматическое заполнение.

Модель Category

Описание: Категория выполнения.

Поля:

  • name — Название категории.

Шаги для выполнения задания:

  1. Создайте модели: В файле models.py вашего приложения добавьте модели с указанными полями и описаниями.
  2. Создайте миграции: Выполните команду для создания миграций: python manage.py makemigrations
  3. Примените миграции: Выполните команду для применения миграций: python manage.py migrate
  4. Зарегистрируйте модели в Admin: В файле admin.py вашего приложения зарегистрируйте все модели.
  5. Зафиксируйте изменения в git: Создайте новый коммит и загрузите его в репозиторий.
  6. Создайте записи через Admin:
    • Создайте суперпользователя.
    • Перейдите в административную панель Django.
    • Добавьте несколько объектов для каждой модели.
  7. Оформите ответ: Прикрепите ссылку на git и скриншоты, где видны созданные объекты.

Подготовка окружения

Шаг 0: Создать папку проекта (если ещё не создана)

# В PowerShell:
mkdir task-manager-project
cd task-manager-project

Шаг 1: Инициализировать git

git init
git checkout -b lesson/16-django-models

Шаг 2: Создать виртуальное окружение

# Создать venv
python -m venv .venv

# Активировать (Windows PowerShell):
.venv\Scripts\activate

# Активировать (Mac/Linux):
source .venv/bin/activate

Шаг 3: Установить Django

pip install django

# Зафиксировать зависимости
pip freeze > requirements.txt

Шаг 4: Создать Django-проект и приложение

# Создать проект (создаст папку task_manager_project/)
django-admin startproject task_manager_project .

# Создать приложение tasks
python manage.py startapp tasks

Шаг 5: Добавить приложение в INSTALLED_APPS

# task_manager_project/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'tasks',    # ← добавить!
]

Шаг 6: Создать .gitignore

# .gitignore
.venv/
__pycache__/
*.pyc
*.pyo
db.sqlite3
*.log
.env

Пошаговое решение

Шаг 1: Написать модели (tasks/models.py)

Логика проектирования:

  • Category объявляем первой — на неё ссылается Task через ManyToMany.
  • Task объявляем до SubTask — SubTask ссылается на Task через ForeignKey.
  • Статусы вынесем в отдельный класс, чтобы не дублировать в Task и SubTask.
  • created_at с auto_now_add=True — заполняется автоматически при создании.
  • unique_for_date='deadline' для title в Task — нельзя создать две задачи с одинаковым названием на одну дату.
# tasks/models.py
from django.db import models


class Category(models.Model):
    """Категория задачи."""
    name = models.CharField(
        max_length=100,
        verbose_name='Название категории'
    )

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = 'Категория'
        verbose_name_plural = 'Категории'
        ordering = ['name']


class Task(models.Model):
    """Основная задача для выполнения."""

    # Статусы вынесены в TextChoices — современный Django 5.x подход
    class Status(models.TextChoices):
        NEW = 'new', 'New'
        IN_PROGRESS = 'in_progress', 'In progress'
        PENDING = 'pending', 'Pending'
        BLOCKED = 'blocked', 'Blocked'
        DONE = 'done', 'Done'

    # title уникально для даты дедлайна: нельзя создать 2 задачи
    # с одинаковым названием на одну дату
    title = models.CharField(
        max_length=200,
        unique_for_date='deadline',
        verbose_name='Название задачи'
    )
    description = models.TextField(
        blank=True,
        verbose_name='Описание'
    )
    # ManyToMany — одна задача может относиться ко многим категориям
    categories = models.ManyToManyField(
        Category,
        blank=True,
        related_name='tasks',
        verbose_name='Категории'
    )
    status = models.CharField(
        max_length=20,
        choices=Status.choices,
        default=Status.NEW,
        verbose_name='Статус'
    )
    # DateTimeField — дата и время дедлайна
    deadline = models.DateTimeField(
        null=True,
        blank=True,
        verbose_name='Дедлайн'
    )
    # auto_now_add=True — заполняется автоматически при создании объекта
    created_at = models.DateTimeField(
        auto_now_add=True,
        verbose_name='Дата создания'
    )

    def __str__(self):
        return f"{self.title} [{self.get_status_display()}]"

    class Meta:
        verbose_name = 'Задача'
        verbose_name_plural = 'Задачи'
        ordering = ['-created_at']


class SubTask(models.Model):
    """Подзадача — часть основной задачи."""

    class Status(models.TextChoices):
        NEW = 'new', 'New'
        IN_PROGRESS = 'in_progress', 'In progress'
        PENDING = 'pending', 'Pending'
        BLOCKED = 'blocked', 'Blocked'
        DONE = 'done', 'Done'

    title = models.CharField(
        max_length=200,
        verbose_name='Название подзадачи'
    )
    description = models.TextField(
        blank=True,
        verbose_name='Описание'
    )
    # ForeignKey — одна Task имеет много SubTask
    # CASCADE — при удалении Task все её SubTask тоже удаляются
    task = models.ForeignKey(
        Task,
        on_delete=models.CASCADE,
        related_name='subtasks',
        verbose_name='Основная задача'
    )
    status = models.CharField(
        max_length=20,
        choices=Status.choices,
        default=Status.NEW,
        verbose_name='Статус'
    )
    deadline = models.DateTimeField(
        null=True,
        blank=True,
        verbose_name='Дедлайн'
    )
    created_at = models.DateTimeField(
        auto_now_add=True,
        verbose_name='Дата создания'
    )

    def __str__(self):
        return f"{self.title} (задача: {self.task.title})"

    class Meta:
        verbose_name = 'Подзадача'
        verbose_name_plural = 'Подзадачи'
        ordering = ['-created_at']

Шаг 2: Зарегистрировать модели в Admin (tasks/admin.py)

Логика: регистрируем все три модели. Для Task добавляем отображение категорий и статуса в списке.

# tasks/admin.py
from django.contrib import admin
from .models import Category, Task, SubTask


@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
    list_display = ('name',)
    search_fields = ('name',)


@admin.register(Task)
class TaskAdmin(admin.ModelAdmin):
    list_display = ('title', 'status', 'deadline', 'created_at')
    list_filter = ('status',)
    search_fields = ('title', 'description')
    filter_horizontal = ('categories',)   # удобный виджет для M2M
    ordering = ('-created_at',)


@admin.register(SubTask)
class SubTaskAdmin(admin.ModelAdmin):
    list_display = ('title', 'task', 'status', 'deadline', 'created_at')
    list_filter = ('status',)
    search_fields = ('title', 'description')
    ordering = ('-created_at',)

Шаг 3: Создать и применить миграции

# Создать файлы миграций
python manage.py makemigrations tasks

# Ожидаемый вывод:
# Migrations for 'tasks':
#   tasks\migrations\0001_initial.py
#     - Create model Category
#     - Create model Task
#     - Create model SubTask

# Применить миграции к БД
python manage.py migrate

# Ожидаемый вывод:
# ...
# Applying tasks.0001_initial... OK

Шаг 4: Создать суперпользователя

python manage.py createsuperuser
# Username: admin
# Email: admin@example.com
# Password: (введите надёжный пароль)
# Password (again): (повторите)
# Superuser created successfully.

Шаг 5: Запустить сервер и проверить Admin

python manage.py runserver
# Сервер запущен: http://127.0.0.1:8000/admin/

Откройте браузер → http://127.0.0.1:8000/admin/ → войдите с логином/паролем суперпользователя.

Шаг 6: Создать тестовые данные

В Admin создайте хотя бы:

  • 2-3 категории (например: «Работа», «Личное», «Учёба»)
  • 2-3 задачи с разными статусами, категориями и дедлайнами
  • 1-2 подзадачи для каждой задачи

Шаг 7: Зафиксировать в git

git add tasks/models.py tasks/admin.py tasks/migrations/
git add requirements.txt .gitignore task_manager_project/settings.py
git commit -m "lesson 16: Task Manager — models Task, SubTask, Category + Admin"
git push origin lesson/16-django-models

Проверка в VS Code

Открыть проект

  1. Откройте VS Code.
  2. Меню File → Open Folder → выберите папку task-manager-project.
  3. VS Code предложит установить расширения Python — нажмите Install All.

Выбрать интерпретатор

  1. Нажмите Ctrl+Shift+P → введите Python: Select Interpreter.
  2. Выберите интерпретатор из .venv.

Настройка launch.json для запуска Django (F5)

Создайте файл .vscode/launch.json:

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Django: runserver",
      "type": "debugpy",
      "request": "launch",
      "program": "${workspaceFolder}/manage.py",
      "args": ["runserver"],
      "django": true,
      "console": "integratedTerminal",
      "env": {
        "PYTHONPATH": "${workspaceFolder}"
      }
    }
  ]
}

Нажмите F5 — Django запустится в режиме отладки. Браузер: http://127.0.0.1:8000/admin/

Точки останова в models.py

  1. Откройте tasks/models.py в VS Code.
  2. Поставьте breakpoint на метод __str__ модели Task (кликните на номер строки).
  3. Нажмите F5 → откройте Admin → откройте список задач.
  4. VS Code остановится на точке — в панели «Variables» можно увидеть self.title, self.status.
  5. F10 — шаг вперёд. F5 — продолжить до следующего breakpoint.

Отладка через Django shell

Для проверки моделей без запуска сервера используйте shell:

# В терминале VS Code (Ctrl+`):
python manage.py shell

# Проверить модели:
from tasks.models import Category, Task, SubTask

# Создать категорию
cat = Category(name='Работа')
cat.save()
print(Category.objects.all())

# Создать задачу
from django.utils import timezone
task = Task(title='Изучить Django', status='new', deadline=timezone.now())
task.save()
task.categories.add(cat)
task.save()
print(Task.objects.all())
print(task.categories.all())

Типичные ошибки при выполнении ДЗ

Ошибка: No module named 'django'

# venv не активирован. Активируйте:
.venv\Scripts\activate   # Windows PowerShell
source .venv/bin/activate  # Mac/Linux
pip install django

Ошибка: makemigrations не видит модели

Приложение tasks не добавлено в INSTALLED_APPS. Добавьте 'tasks' в список.

Ошибка: ManyToManyField через M2M без blank=True требует значения

# Неверно:
categories = models.ManyToManyField(Category)  # форма требует категорию

# Верно для необязательных M2M:
categories = models.ManyToManyField(Category, blank=True)

Ошибка: ForeignKey без on_delete

# Неверно:
task = models.ForeignKey(Task)  # TypeError в Django 5.x

# Верно:
task = models.ForeignKey(Task, on_delete=models.CASCADE)

Ошибка: unique_for_date требует DateTimeField с соответствующим именем

# unique_for_date='deadline' означает: title уникально для значения поля deadline
# Поле deadline должно быть DateField или DateTimeField
title = models.CharField(max_length=200, unique_for_date='deadline')
deadline = models.DateTimeField(null=True, blank=True)  # должно существовать!
Полезные ссылки:

Как сдать задание

  1. Убедитесь, что python manage.py runserver запускается без ошибок.
  2. Войдите в Admin (http://127.0.0.1:8000/admin/) и убедитесь, что модели Task, SubTask, Category видны.
  3. Создайте как минимум 2 категории, 2 задачи, 2 подзадачи через Admin.
  4. Сделайте скриншоты списков объектов в Admin.
  5. Добавьте файлы в git и создайте коммит:
    git add tasks/models.py tasks/admin.py tasks/migrations/
    git add requirements.txt .gitignore
    git commit -m "lesson 16: Task Manager — models + Admin"
    git push origin lesson/16-django-models
  6. Вставьте ссылку на репозиторий и прикрепите скриншоты в LMS.