Меню для django сайта

19 Сен 2016 , 10882

Как-то мне понадобилось реализовать меню на сайте, где пункты меню брались из базы данных.

На сайтах, которые я ранее писал на PHP это реализовывалось довольной легко, а вот на DJANGO я сразу не мог это реализовать. Самый топорный , это конечно же передавать пункты меню в шаблон в каждой вьюхе ))

Но погуглив , я понял, что это реализуется довольно легко с помощью пользовательских template tags.Но для новичков ,это вначале проблематично и поэтому это статья для них.

Создадим новый app


python manage.py startapp cms

В файле models.py создадим модель для Menu.


from django.db import models


class Menu(models.Model):
    name = models.CharField('Название', max_length=100)
    url = models.CharField('Ссылка', max_length=255)
    position = models.PositiveIntegerField('Позиция', default=1)

    def __str__(self):
        return str(self.name)

    class Meta:
        ordering = ('position',)
        verbose_name = 'Пункт меню'
        verbose_name_plural = Пункты меню'


Внутри нашего приложения cms создадим папку templatetags. Внутри этой папки создайте пустой файл __init__.py

В папке templatetags создадим файл common_tags.py


from django import template
from cms.models import Menu
register = template.Library()


@register.inclusion_tag('menu.html', takes_context=True)
def show_top_menu(context):
    menu_items = Menu.objects.all()
    return {
        "menu_items": menu_items,
    }

Содержимое файла menu.html


<ul class="menu">
{% for m_item in menu_items %}
    <li><a href="{{ m_item.url }}">{{ m_item.name }}</a></li>
{% endfor %}
</ul>


Мы создали наш шаблонный включаемый тег с названием show_top_menu с помощью метода inclusion_tag. Ему нужно передать в качестве параметра путь к файлу шаблона (в нашем случае menu.html), где будет html код. Туда мы можем передать пункты меню и другие параметры, которые нужно вывести.

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


{% load common_tags %}

# В нужном месте вставляете ваше меню
{% show_top_menu %}

Древовидное меню

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

Установим библиотеку django-mptt для работы с древовидными структурами


pip install django-mptt

Добавим эту либу в наш settings.py


INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'mptt', #Добавляем django-mptt
    'core', 
]

Не забудьте создать с помощью startapp проект core , где мы будем хранить наши модели с пунктами меню.

Создаем модель в core/models.py , где будем хранить пункты меню.


from django.db import models
from mptt.models import MPTTModel, TreeForeignKey


class MenuItem(MPTTModel):
    name = models.CharField(max_length=100, unique=True)
    url = models.CharField('Ссылка', max_length=255)
    position = models.PositiveIntegerField('Позиция', default=1)
    parent = TreeForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children')

    class MPTTMeta:
        order_insertion_by = ['position']

    def __str__(self):
        return str(self.name)

    class Meta:
        verbose_name = 'Пункт меню'
        verbose_name_plural = 'Пункты меню'

Чтобы редактировать эти пункты в меню через админку мы файл core/admin.py добавим следующий код.


from django.contrib import admin
from mptt.admin import MPTTModelAdmin
from core.models import MenuItem


class MenuItemMPTTModelAdmin(MPTTModelAdmin):
    mptt_level_indent = 20


admin.site.register(MenuItem, MenuItemMPTTModelAdmin)

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

Добавим show_menu в файл core/templatetags/common_tags.py


from django import template
from core.models import MenuItem
register = template.Library()


@register.inclusion_tag('templatetags/menu.html', takes_context=True)
def show_menu(context):
    menu_items = MenuItem.objects.filter(level=1)
    return {
        "menu_items": menu_items,
    }

Добавим html код , где будет формироваться меню .Этот файл core/templates/templatetags/menu.html




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




Итого получим вот такой результат

Весь тестовый проект доступен на Github

Заключение

В данной статье бы показан как с помощью пользовательских шаблонных тегов выводить пункты меню. В частности для этого был использован метод inclusion_tag.

Если будут вопросы , то с радостью отвечу на них в комментариях

comments powered by Disqus

Подписка

Подпишитесь на наш список рассылки, чтобы получать обновления из блога

Рубрики

Теги