Wagtail Custom URL 基于 slugs 使用 RoutablePageMixin
Wagtail Custom URL based on slugs using RoutablePageMixin
我想更改博客条目的 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
暂时把 RoutablePageMixin
放在一边,Wagtail 需要理解的一点是,你不应该像对待常规 Django 网站(或 Rails 或任何将路由映射到 views/controllers 的框架。使用 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/)
|- ...
\- ...
在这种情况下,您不需要任何进一步的处理。这很简单,您可以免费获得类别页面,其中可以列出该类别中的所有 post。显然,这种解决方案的缺点是这样 post 只能属于一个类别。
现在让我们看看 RoutablePageMixin
是如何工作的以及它们可以提供什么。它们允许您创建虚拟页面(树中不存在的页面)。他们通过给路径加上后缀来实现这一点,例如您在 /blog/
有一个 BlogIndexPage
,但您还想在 /blog/archives/<the-year>/
提供年度档案,在 /blog/tags/<the-tag>
提供标签过滤。你可以想到的方式(免责声明:这不是它实际工作的方式)是当 Wagtail 收到对 /blog/archives/<the-year>/
的请求时,这条路径将不存在于树中(/blog/archives/
也不会),但是 /blog/
会,所以 Wagtail 会加载您的可路由页面并检查匹配 /archives/<the-year>
的路由(因为它已经解析 /blog/
)。
因此,如果您想修改当前页面路径之前的内容,RoutablePageMixin
必须是树中父页面声明的一部分。假设您的 PostPage
es 是您主页的直接子级,如下所示:
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/)
然后你会在 HomePage
:
的声明中包含 RoutablePageMixin
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)
但是现在你遇到了一个问题,因为你的 posts 在技术上存在于 2 个不同的 URLs,即 /<category_slug>/<page_slug>/
(因为 RoutablePageMixin)和 /<page_slug>/
(因为它在树中的位置)。您可以接受它并简单地设置 canonical URL 或使您的 post 重定向到正确的 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)
也就是说,我建议不要使用 redirect
。这确实违背了 Wagtail 的核心原则。
如果您确实更改了 URL 结构,使其与 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),
}
]
我想更改博客条目的 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
暂时把 RoutablePageMixin
放在一边,Wagtail 需要理解的一点是,你不应该像对待常规 Django 网站(或 Rails 或任何将路由映射到 views/controllers 的框架。使用 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/)
|- ...
\- ...
在这种情况下,您不需要任何进一步的处理。这很简单,您可以免费获得类别页面,其中可以列出该类别中的所有 post。显然,这种解决方案的缺点是这样 post 只能属于一个类别。
现在让我们看看 RoutablePageMixin
是如何工作的以及它们可以提供什么。它们允许您创建虚拟页面(树中不存在的页面)。他们通过给路径加上后缀来实现这一点,例如您在 /blog/
有一个 BlogIndexPage
,但您还想在 /blog/archives/<the-year>/
提供年度档案,在 /blog/tags/<the-tag>
提供标签过滤。你可以想到的方式(免责声明:这不是它实际工作的方式)是当 Wagtail 收到对 /blog/archives/<the-year>/
的请求时,这条路径将不存在于树中(/blog/archives/
也不会),但是 /blog/
会,所以 Wagtail 会加载您的可路由页面并检查匹配 /archives/<the-year>
的路由(因为它已经解析 /blog/
)。
因此,如果您想修改当前页面路径之前的内容,RoutablePageMixin
必须是树中父页面声明的一部分。假设您的 PostPage
es 是您主页的直接子级,如下所示:
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/)
然后你会在 HomePage
:
RoutablePageMixin
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)
但是现在你遇到了一个问题,因为你的 posts 在技术上存在于 2 个不同的 URLs,即 /<category_slug>/<page_slug>/
(因为 RoutablePageMixin)和 /<page_slug>/
(因为它在树中的位置)。您可以接受它并简单地设置 canonical URL 或使您的 post 重定向到正确的 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)
也就是说,我建议不要使用 redirect
。这确实违背了 Wagtail 的核心原则。
如果您确实更改了 URL 结构,使其与 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),
}
]