使用RoutablePageMixin基于的Wagtail自定义URL

AJH*_*AJH 2 django wagtail

我想更改博客条目的URL,以包括类别的条目(@route(r'^([category-slug]/[post-slug]例如-localost / health / health_blog_1)。

我将如何更改此模型?

class PostPage(RoutablePageMixin, Page):
    body = RichTextField(blank=True)
    date = models.DateTimeField(verbose_name="Post date", default=datetime.datetime.today)
    categories = ParentalManyToManyField('blog.BlogCategory', blank=True)
    tags = ClusterTaggableManager(through='blog.BlogPageTag', blank=True)

    content_panels = Page.content_panels + [
        FieldPanel('body', classname="full"),
        FieldPanel('categories', widget=forms.CheckboxSelectMultiple),
        FieldPanel('tags'),
    ]

    settings_panels = Page.settings_panels + [
        FieldPanel('date'),
    ]

    @property
    def blog_page(self):
        return self.get_parent().specific

    def get_context(self, request, *args, **kwargs):
        context = super(PostPage, self).get_context(request, *args, **kwargs)
        context['blog_page'] = self.blog_page
        return context
Run Code Online (Sandbox Code Playgroud)

Loï*_*ira 5

撇开RoutablePageMixin片刻,使用Wagtail可以理解的一点是,您不应以与常规Django网站(或Rails或任何将路线映射到视图/控制器的框架)相同的方式来考虑URL。使用Wagtail,从页面树构建页面的路径。因此,如果您希望类别显示在路径中,则它必须是树的一部分。在您的情况下,将是这样的:

HomePage (title: My Website, path: /)
|- CategoryPage (title: Health, path: /health/)
|  |- PostPage (title: Post 1, path: /health/post-1/)
|  |- PostPage (title: Post 2, path: /health/post-2/)
|  \- PostPage (title: Post 3, path: /health/post-3/)
\- CategoryPage (title: Diet, path: /diet/)
|- ...
\- ...
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您不需要任何进一步的操作。很简单,您可以免费获得类别页面,其中可以列出该类别中的所有帖子。显然,此解决方案的缺点是,帖子只能以这种方式属于一个类别。

现在,让我们看看他们RoutablePageMixin的工作方式以及他们能提供什么。它们允许您创建虚拟页面(树中不存在的页面)。他们通过添加路径后缀来实现此目的,例如,您有个BlogIndexPageat,/blog/但您还想提供的年度存档/blog/archives/<the-year>/和过滤的标签/blog/tags/<the-tag>。您可以想到的方式(免责声明:这并不是它的实际工作方式)是,当Wagtail收到请求时/blog/archives/<the-year>/,该路径在树中将不存在(也不会/blog/archives/),但是/blog/确实存在,因此Wagtail负载是可路由的页并检查匹配的路由/archives/<the-year>(因为它已解决/blog/)。

因此,如果您想修改当前页面路径之前的内容,则RoutablePageMixin必须是树中父页面声明的一部分。假设您的PostPagees是您的首页的直接子代,如下所示:

HomePage (title: My Website, path: /)
|- PostPage (title: Post 1, path: /health/post-1/)
|- PostPage (title: Post 2, path: /health/post-2/)
\- PostPage (title: Post 3, path: /health/post-3/)
Run Code Online (Sandbox Code Playgroud)

然后,您将RoutablePageMixin在的声明中包括HomePage

form django.shortcuts import get_object_or_404
from wagtail.contrib.routable_page.models import RoutablePageMixin, route
from wagtail.core.models import Page

class HomePage(RoutablePageMixin, Page):
    # Some fields

    @route(r'^(?P<category_slug>[\w-]+)/(?P<page_slug>[\w-]+)')
    def post_page(self, requets, category_slug, page_slug):
        post = get_object_or_404(PostPage, slug=page_slug, category_slug=category_slug)
        context = {
            'post': post
        }
        return render(request, 'posts/post_page.html', context)
Run Code Online (Sandbox Code Playgroud)

但是现在您遇到了一个问题,因为您的帖子在技术上存在于2个不同的URL,即/<category_slug>/<page_slug>/(由于RoutablePageMixin)和/<page_slug>/(由于其在树中的位置)。您可以使用它,只需设置规范的URL或将帖子重定向到正确的URL:

form django.shortcuts import redirect
from wagtail.core.models import Page

class PostPage(Page):
    # Some fields

    def serve(self, request, *args, **kwargs):
        homepage = self.get_parent().specific
        url = homepage.url + homepage.reverse_subpage('post_page', category_slug=self.category_slug, page_slug=self.page_slug)
        return redirect(url)
Run Code Online (Sandbox Code Playgroud)

话虽如此,我建议不要使用redirect。这确实使Wagtail违背了其核心原则。

如果您确实更改了网址结构,因此与Wagtail的树形路径不匹配,则还需要考虑更改站点地图网址。

class PostPage(Page):

    def serve(..):
        ....

    def get_sitemap_urls(self, request):
        """Overwrite the url."""
        return [
            {
                "location": '',  # Reverse subpage url
                "lastmod": (self.last_published_at or self.latest_revision_created_at),
            }
        ]
Run Code Online (Sandbox Code Playgroud)