创建自定义网址w

时间:2020-01-12 02:21:05

标签: django url wagtail wagtail-pageurl

我有一个结构类似的网站:

首页:动物
子页面:猫
子页面:狗

首页:猫
子页面:食物

首页:狗
子页面:食物

这样,用户可以转到站点/动物或站点/猫。动物是高级信息,猫和狗是站点的更详细部分。

我要做什么:
有时,我希望能够重用Animals中的页面并将其用于Cat或Dog中。但我不希望该网址从一个部分切换到另一部分。

示例:如果用户位于“动物”下,并且他们单击食品文章,则网址应为: animals/cats/food_article

如果他们在cats下单击同一篇文章,则网址应如下所示: cats/food_article

我尝试过的事情
我尝试使用RoutableRouteMixin。但这适用于子页面,不适用于同一级别的页面。

我尝试覆盖文章模型的get_url_parts方法。但是随后出现404错误,因为页面实际上并不存在于我创建的url中。

这可以在Wa中实现吗?还是有可以与Wagtail一起使用的Django解决方案?

2 个答案:

答案 0 :(得分:1)

您可以如下创建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中的服务功能以进行匹配。 但是,这可能取决于您的网站。

答案 1 :(得分:1)

潜在方法

  • 无需进行重大自定义,您将需要为文章添加单独的页面模型,可以将其添加到根页面下,然后默认情况下不显示(包括从任何菜单设置中隐藏的页面)。
  • 然后创建一个modelcluster,它将作为动物页面(猫,狗)和文章页面之间的关系。
  • 最后,覆盖动物页面的get_children方法,该方法位于每个Page上,并且来自django-treebeard。路由逻辑使用此方法来确定页面是否是另一个页面的子页面(读取URL时)。
  • 一旦创建了几个AnimalPage,然后创建了ArticlePage(例如,食品文章),然后进入狗页和猫页,并将食品文章链接到该页面。
  • 这时您将可以通过3个URL访问食品文章; http://localhost:8000/food-article/http://localhost:8000/animals/cats/food-article/http://localhost:8000/animals/dogs/food-article/
  • 您可以通过几种不同的方式使原始食品文章网址无法正常工作,但最简单的方法是将所有ArticlePage置于其自己的父页面下,然后使用routablemixin使该页面不显示任何内容子网址。
    • 注意:如果您将所有文章都放在其自己的子页面下(例如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