Создать собственный трясогузку URL

У меня есть сайт, который я структурировал так:

Первая страница: Животные Дополнительная
страница: Кошка Дополнительная
страница: Собака

Первая страница: Кот
Подстраница: Еда

Первая страница: Собака
Подстраница: Еда

Таким образом, пользователь может перейти на сайт / животные или сайт / кошка. Животные - это общая информация, Кот и Собака - более подробные разделы сайта.

Что я хочу сделать:
иногда мне хочется иметь возможность повторно использовать страницы из Animals и использовать их в Cat или Dog. Но я не хочу, чтобы URL-адрес переключался с одного раздела на другой.

Пример: если пользователь находится в разделе "Животное" и щелкает статью о продукте, URL-адрес должен быть таким:animals/cats/food_article

Если они нажмут на ту же статью под кошками, URL-адрес должен выглядеть так:cats/food_article

Что пробовал:
пробовал использоватьRoutableRouteMixin. Но это работает для подстраниц, а не для страниц того же уровня.

Я попытался перезаписать get_url_partsметод для моделей изделий. Но затем я получил ошибку 404, потому что страницы на самом деле не существовали по созданному мной URL.

Можно ли этого добиться в трясогузке? Или есть решение Django, которое я могу использовать с Wagtail?

2 ответа

Возможный подход

  • Без серьезной настройки вам нужно будет добавить отдельную модель страницы для ваших статей, их можно добавить под корневую страницу, а затем просто не показывать по умолчанию (включая скрытые из любых настроек меню).
  • Затем создайте модельный кластер, который будет взаимосвязью между вашими страницами с животными (кошка, собака) и страницами статей.
  • Наконец, переопределите страницу Animal get_children метод, который есть на каждом Page и происходит из django-treebeard. Этот метод используется логикой маршрутизации, чтобы определить, является ли страница дочерней по отношению к другой (при чтении URL-адреса).
  • Как только вы создадите несколько AnimalPages, затем создайте ArticlePage (например, статья о продуктах питания), затем перейдите на страницу с собаками и кошками и свяжите статью о продуктах питания со страницей.
  • На этом этапе вы сможете получить доступ к статье о еде по 3 URL-адресам; http://localhost:8000/food-article/, http://localhost:8000/animals/cats/food-article/ а также http://localhost:8000/animals/dogs/food-article/.
  • Вы можете сделать так, чтобы исходный URL-адрес статьи о еде не работал несколькими способами, но самый простой способ - поставить все ArticlePages на своей родительской странице, а затем используйте routablemixin, чтобы эта страница не показывала никаких дополнительных URL-адресов.
    • Примечание. Если вы разместите все статьи на отдельной подстранице (например, ArticlesPage, это все равно должно работать, поскольку проверяется только "последний" раздел URL-адреса). Однако я не проверял это.

Пример кода

from django.db import models

from modelcluster.fields import ParentalKey
from modelcluster.models import ClusterableModel

from wagtail.admin.edit_handlers import (
    InlinePanel,
    PageChooserPanel,
)

from wagtail.core.models import Orderable, Page

class ArticlePage(Page):
    # Articles will be available to link to any other AnimalPage and content shared

    content_panels = Page.content_panels

    subpage_types = [] # no sub-pages allowed

class RelatedArticle(models.Model):
    # http://docs.wagtail.io/en/v2.7.1/reference/pages/panels.html#inline-panels
    article_page = models.ForeignKey(
        'wagtailcore.Page',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+',
    )

    panels = [
        PageChooserPanel('article_page', 'base.ArticlePage')
    ]

    class Meta:
        abstract = True

class ArticlePageRelatedPages(Orderable, RelatedArticle):
    page = ParentalKey(
        'base.AnimalPage',
        on_delete=models.CASCADE,
        related_name='related_articles'
    )

class AnimalsPage(Page):
    # This is our root animals page

    content_panels = Page.content_panels

    subpage_types = ['AnimalPage']


class AnimalPage(Page):

    def get_articles(self):
        # returns a queryset (not a list) of all Pages that are linked articles
        return Page.objects.filter(id__in=[
            r.article_page.pk for r in self.related_articles.all()
        ])

    def get_children(self):
        # override the method from django-treebeard
        # can be used in the template or wherever needed for 'children'
        # this method is also used when attempting to find child urls
        sub_pages = super().get_children()
        articles = self.get_articles()
        return articles | sub_pages # merges the two querysets for the 'or' operator

    content_panels = Page.content_panels + [
        InlinePanel('related_articles', label='Related Articles'),
    ]

    subpage_types = [] # no sub-pages allowed

Вы можете создать IncludePage, как показано ниже, и использовать его для представления того же контента под другим URL-адресом.

from django.db import models
from wagtail.core.models import Page
from wagtail.admin.edit_handlers import PageChooserPanel
from django.http import Http404


class IncludePage(Page):
    page  = models.ForeignKey('wagtailcore.Page',
                              null=True, blank=True,
                              on_delete=models.SET_NULL,
                              related_name='+')

    content_panels = Page.content_panels + [
              PageChooserPanel('page'),
             ]

    def get_template(self, *args, **kwargs):
        page = self.page.specific
        if type(page) == IncludePage:
            raise Http404("Avoid recursion")
        return page.get_template(*args, **kwargs)

    def get_context(self, *args, **kwargs):
        page = self.page.specific
        if type(page) == IncludePage:
            raise Http404("Avoid recursion")
        return page.get_context(*args, **kwargs)

Обратите внимание, однако, что это не будет работать для страниц с настраиваемыми функциями обслуживания (например, страниц, использующих RoutableRouteMixin). Для тех, кому вам нужно будет продублировать функциональность обслуживания в IncludePage, чтобы соответствовать. Но в зависимости от вашего сайта это может быть полезно.

Другие вопросы по тегам