Django База [2023]: Создание вложенных категорий с помощью MPTT 🌳 #3
Django

Django База [2023]: Создание вложенных категорий с помощью MPTT 🌳 #3

Razilator

В этой статье мы рассмотрим создание древовидной модели категорий для статей в Django 4.1 с использованием MPTT модуля.

Создание вложенной модели категорий (Category)

Перейдем в наше приложение blog и в модели. В прошлом уроке мы создали модель Article

Откройте терминал и запишите следующую команду для установки Django MPTT и Pillow для работы с полем thumbnail: models.ImageField с помощью команды pip install django-mptt Pillow

После установки модуль MPTT необходимо добавить в INSTALLED_APPS:

backend/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'modules.blog.apps.BlogConfig',
    'mptt',
]

Теперь перейдем к созданию самой модели Category:

blog/models.py
from mptt.models import MPTTModel, TreeForeignKey

class Category(MPTTModel):
    """
    Модель категорий с вложенностью
    """
    title = models.CharField(max_length=255, verbose_name='Название категории')
    slug = models.SlugField(max_length=255, verbose_name='URL категории', blank=True)
    description = models.TextField(verbose_name='Описание категории', max_length=300)
    parent = TreeForeignKey(
        'self',
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        db_index=True,
        related_name='children',
        verbose_name='Родительская категория'
    )

    class MPTTMeta:
        """
        Сортировка по вложенности
        """
        order_insertion_by = ('title',)

    class Meta:
        """
        Сортировка, название модели в админ панели, таблица в данными
        """
        verbose_name = 'Категория'
        verbose_name_plural = 'Категории'
        db_table = 'app_categories'

    def __str__(self):
        """
        Возвращение заголовка статьи
        """
        return self.title

Пояснения:

  • order_insertion_by - сортировка по вложенностям
  • Наследуемся от MPTTModel

Далее нам необходимо включить категории в модель статей, делается это следующим образом:

blog/models.py
class Article(models.Model):
    """
    Модель постов для сайта
    """    
    title = models.CharField(verbose_name='Заголовок', max_length=255)
    slug = models.CharField(verbose_name='Альт.название', max_length=255, blank=True, unique=True)
    # Другие поля модели...
    category = TreeForeignKey('Category', on_delete=models.PROTECT, related_name='articles', verbose_name='Категория')

Мы должны использовать вместо отношения: ForeignKey импортированное отношение вложенности из модуля MPTT: TreeForeignKey

Регистрируем модель категорий в админке, и добавляем возможность скрывать категории по вложенностям с помощью DraggableMPTTAdmin: До этого мы регистрировали уже модель Article.

blog/admin.py
from django.contrib import admin

from mptt.admin import DraggableMPTTAdmin
from .models import Category, Article

@admin.register(Category)
class CategoryAdmin(DraggableMPTTAdmin):
    """
    Админ-панель модели категорий
    """
    list_display = ('tree_actions', 'indented_title', 'id', 'title', 'slug')
    list_display_links = ('title', 'slug')
    prepopulated_fields = {'slug': ('title',)}

    fieldsets = (
        ('Основная информация', {'fields': ('title', 'slug', 'parent')}),
        ('Описание', {'fields': ('description',)})
    )

admin.site.register(Article)

Отлично. Теперь нам необходимо провести миграции в базу данных:

Терминал
py manage.py makemigrations
py manage.py migrate

Результат выполнения команд:

Терминал
(venv) PS C:\Users\Razilator\Desktop\Base\backend> py manage.py makemigrations
Migrations for 'blog':
  modules\blog\migrations\0001_initial.py
    - Create model Category
    - Create model Article
    - Create index app_article_time_cr_a1fcc0_idx on field(s) -time_create, -fixed of model article
(venv) PS C:\Users\Razilator\Desktop\Base\backend> python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, blog, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying blog.0001_initial... OK
  Applying sessions.0001_initial... OK
(venv) PS C:\Users\Razilator\Desktop\Base\backend> 

Отлично, миграции проведены. Теперь давайте проверим работоспособность наших моделей в админ-панеле, чтобы в нее войти нам нужно создать супер-пользователя, делается это следующей командой: py manage.py createsuperuser

Вводим свои данные:

Терминал
Username: Ваш логин
Email address: Ваш Email
Password: Ваш пароль
Password (again): Повтор Вашего пароля

Если все ввели правильно, то пользователь будет создан: Superuser created successfully.

Далее переходим в админ-панель по следующему адресу: http://127.0.0.1:8000/admin/, авторизовываемся и должно получиться вот так:

Админка с моделями
Админка с моделями

Отлично, давайте создадим вложенные категории:

Сначала делаем главную категорию:

Root категория
Root категория

Далее добавляем вложенную категорию, например Django

Вложенная категория Django
Вложенная категория Django

Также пример как выглядит возможность скрыть категории по вложенности:

DraggableMPTTAdmin
DraggableMPTTAdmin

И напоследок добавим статью:

Первая статья добавленная в админке
Первая статья добавленная в админке

Отлично, у нас все получилось. Вскоре я напишу продолжение по работе по базовому Django.

;