Сейчас загружается

Создать гибкую систему меню в Django

Создать гибкую систему меню в Django

Чтобы создать гибкую систему меню, похожую на WordPress, вам нужно реализовать модели для меню и пунктов меню, с возможностью динамического выбора URL-адресов для каждой страницы, категории или записи блога. Вот шаги, которые помогут вам это сделать.

1. Создайте модели для меню и пунктов меню

Начнем с создания двух моделей: Menu для хранения основного меню и MenuItem для пунктов меню, которые могут ссылаться на страницы, категории или посты блога.

# app/models.py
from django.db import models
from django.urls import reverse

class Menu(models.Model):
    name = models.CharField("Название меню", max_length=100, unique=True)

    def __str__(self):
        return self.name

class MenuItem(models.Model):
    menu = models.ForeignKey(Menu, related_name="items", on_delete=models.CASCADE)
    title = models.CharField("Заголовок", max_length=100)
    url = models.CharField("URL", max_length=255, blank=True, help_text="URL или выбрать страницу, категорию, пост")
    page = models.ForeignKey('Page', blank=True, null=True, on_delete=models.SET_NULL, help_text="Выберите страницу")
    blog_category = models.ForeignKey('BlogCategory', blank=True, null=True, on_delete=models.SET_NULL, help_text="Выберите категорию блога")
    blog_post = models.ForeignKey('BlogPost', blank=True, null=True, on_delete=models.SET_NULL, help_text="Выберите пост блога")
    order = models.PositiveIntegerField("Порядок", default=0)

    class Meta:
        ordering = ['order']

    def save(self, *args, **kwargs):
        # Приоритет URL, если он указан вручную
        if not self.url:
            if self.page:
                self.url = reverse('page_detail', args=[self.page.slug])
            elif self.blog_category:
                self.url = reverse('blog_category_detail', args=[self.blog_category.slug])
            elif self.blog_post:
                self.url = reverse('blog_post_detail', args=[self.blog_post.slug])
        super().save(*args, **kwargs)

    def __str__(self):
        return self.title

2. Зарегистрируйте модели в админпанели

Настроим админпанель, чтобы можно было добавлять пункты меню к каждому меню в виде inline-элементов. Это позволит вам организовать иерархию и порядок меню.

# app/admin.py
from django.contrib import admin
from .models import Menu, MenuItem

class MenuItemInline(admin.TabularInline):
    model = MenuItem
    extra = 1

@admin.register(Menu)
class MenuAdmin(admin.ModelAdmin):
    inlines = [MenuItemInline]
    list_display = ("name",)

3. Настройте маршруты (urls.py)

Убедитесь, что у вас есть соответствующие URL-шаблоны для страниц, категорий и постов, которые соответствуют именам в reverse. Например:

# app/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('page/<slug:slug>/', views.page_detail, name='page_detail'),
    path('blog/category/<slug:slug>/', views.blog_category_detail, name='blog_category_detail'),
    path('blog/post/<slug:slug>/', views.blog_post_detail, name='blog_post_detail'),
]

4. Создайте представление для получения меню

Добавьте в представления функцию, которая будет извлекать меню по имени и передавать его в шаблон.

# app/views.py
from django.shortcuts import render, get_object_or_404
from .models import Menu

def get_menu(name):
    return get_object_or_404(Menu, name=name)

5. Выведите меню в шаблоне

Теперь можно динамически выводить меню в любом шаблоне, используя имя меню для загрузки его элементов.

  1. Создайте включаемый шаблон для меню, например, menu.html:
<!-- templates/menu.html -->
<ul>
    {% for item in menu.items.all %}
        <li><a href="{{ item.url }}">{{ item.title }}</a></li>
    {% endfor %}
</ul>

2. Включите меню в нужный шаблон и передайте его через представление.

В представлении можно передать меню в контекст:

def some_view(request):
    menu = get_menu('Main Menu')  # Замените 'Main Menu' на имя меню
    return render(request, 'some_template.html', {'menu': menu})

3. В some_template.html вставьте меню:

{% include 'menu.html' with menu=menu %}

6. Подключите меню к любым шаблонам

Добавьте вызов меню в нужных шаблонах. Например, если меню должно отображаться на всех страницах, его можно добавить в базовый шаблон.

Теперь вы можете добавлять, редактировать и организовывать меню и пункты меню в админпанели, а также динамически выводить их в шаблонах.