M
M
Maxim Barabanov2015-08-21 23:22:42
Django
Maxim Barabanov, 2015-08-21 23:22:42

How do you implement a menu in a Django site?

The task is to make the site menu as flexible and easily customizable as possible. Ideally, as close as possible to the menu management in Drupal, where nodes can be hooked into the menu right from the interface for editing them.
For this, the base class Page was made, from which all pages pinned in the menu are inherited.

class Page(models.Model):
    title = models.CharField(verbose_name="название", max_length=50)
    text = RichTextField(verbose_name="содержимое страницы")
    slug = AutoSlugField(populate_from='title', editable=True)
    objects = InheritanceManager()

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        from django.core.urlresolvers import reverse
        return reverse('app.views.page_details', args=[str(self.slug)])

    class Meta:
        verbose_name = "страница"
        verbose_name_plural = "страницы"

the menu itself consists of MenuItem elements, from which more specific ones can be inherited, such as PageMenuItem
class MenuItem(models.Model):
    title = models.CharField(verbose_name="название", max_length=50)
    description = models.CharField(verbose_name="описание", max_length=100, null=True, blank=True)
    weight = models.PositiveSmallIntegerField(verbose_name="вес", default=0)
    parent = models.ForeignKey('MenuItem', verbose_name="родительский пункт", null=True, blank=True)
    objects = InheritanceManager()

    def __str__(self):
        return self.title

    def url(self):
        return "#"

    def as_dict(self):
        return dict(
            id=self.id,
            title=self.title,
            description=self.description,
            weight=self.weight,
            url=self.url()
        )

    def children(self):
        menu_objects = MenuItem.objects.filter(parent=self).select_subclasses()
        menu_list = list()
        for menu_item in menu_objects:
            item = menu_item.as_dict()
            item['items'] = menu_item.children()
            menu_list.append(item)
        return menu_list

    class Meta:
        verbose_name = "пункт меню"
        verbose_name_plural = "пункт меню"
        ordering = ['weight']


class PageMenuItem(MenuItem):
    page = models.OneToOneField(Page, verbose_name="страница")

    def url(self):
        page = Page.objects.get_subclass(id=self.page_id)
        return page.get_absolute_url()

Everything seems to be fine, but the question arose - how can I add menu items leading to pages - lists of objects? Singletons are spinning in my head, for which one could simply specify an activity attribute, weight, and a display name with a description, but django has a hard time with them - django_solo makes them with fixed id=1, which is not applicable in the case of inheritance.
Are there any more beautiful options?

Answer the question

In order to leave comments, you need to log in

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question