【问题标题】:Create custom url wagtail创建自定义 url wagtail
【发布时间】:2020-01-12 02:21:05
【问题描述】:

我的网站结构如下:

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

首页:猫
子页面:食物

首页:狗
子页面:食物

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

我想做的事:
有时,我希望能够重用 Animals 中的页面并在 Cat 或 Dog 中使用它们。但我不希望 url 从一个部分切换到另一个部分。

示例:如果用户在 Animal 下,并且他们点击食物文章,则 url 应该是: animals/cats/food_article

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

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

我尝试覆盖文章模型的get_url_parts 方法。但是后来我收到了 404 错误,因为这些页面实际上并不存在于我创建的网址中。

这可以在 Wagtail 中实现吗?或者是否有我可以与 Wagtail 一起使用的 Django 解决方案?

【问题讨论】:

    标签: django url wagtail wagtail-pageurl


    【解决方案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)
    

    请注意,但这不适用于具有自定义服务功能的页面 (例如,使用 RouterRouteMixin 的页面)。对于那些你必须 在 IncludePage 中复制服务功能以进行匹配。 但根据您的网站,这可能会有用。

    【讨论】:

      【解决方案2】:

      可能的方法

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-06-13
        • 2017-07-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多