Создать пользовательский URL-трясогузка - PullRequest
0 голосов
/ 12 января 2020

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

Верхняя страница: животные
Подстраница: кошка
Подстраница: собака

Верхняя страница: кошка
Подстраница: еда

Верхняя страница: собака
Подстраница: еда

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

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

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

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

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

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

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

Ответы [ 2 ]

1 голос
/ 12 января 2020

Потенциальный подход

  • Без серьезной настройки вам потребуется добавить отдельную модель страницы для ваших статей, их можно добавить на странице root, а затем просто не показывать по умолчанию (включая скрыто в любой настройке вашего меню).
  • Затем создайте модельный кластер , который будет связывать страницы вашего животного (кошка, собака) и страницы статьи.
  • Наконец, переопределите метод get_children страницы Animal, который есть у каждого Page и происходит от django-treebeard. Этот метод используется логикой маршрутизации c, чтобы определить, является ли страница дочерней по отношению к другой (при чтении URL-адреса).
  • После создания нескольких AnimalPage s создайте ArticlePage (например, Food Article), затем go на страницу собаки и страницу кошки и свяжите статью еды с этой страницей.
  • На этом этапе вы сможете получить доступ к статье еды по 3 URL; http://localhost:8000/food-article/, http://localhost:8000/animals/cats/food-article/ и http://localhost:8000/animals/dogs/food-article/.
  • Вы можете сделать так, чтобы исходный URL-адрес пищевой статьи не работал несколькими различными способами, но самый простой способ - поместить все ArticlePage в свои собственные родительской страницы, а затем используйте 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
1 голос
/ 12 января 2020

Вы можете создать 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, чтобы соответствовать. Но в зависимости от вашего сайта это может быть полезно.

...