Wagtail Пользовательский URL на основе слагов с использованием RoutablePageMixin - PullRequest
0 голосов
/ 14 января 2019

Я хотел бы изменить 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

1 Ответ

0 голосов
/ 14 января 2019

Оставляя RoutablePageMixin на мгновение, кое-что, что нужно понять с Wagtail, это то, что вы не должны думать об URL-адресах так же, как с обычным веб-сайтом Django (или Rails или любой другой средой, которая отображает маршруты на представления / контроллеры). ). В 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/)
|- ...
\- ...

В этом сценарии вам больше не понадобится калечить. Это просто, и вы получаете страницы категорий бесплатно, которые могут перечислить все сообщения в этой категории. Очевидно, что недостатком этого решения является то, что сообщение может принадлежать только одной категории.

Теперь посмотрим, как работают * 1007 и что они могут предложить. Они позволяют вам создавать виртуальные страницы (страницы, которых нет в дереве). Они достигают этого путем суффикса пути, например, у вас есть BlogIndexPage на /blog/, но вы также хотите предоставлять годовые архивы на /blog/archives/<the-year>/ и фильтрацию тегов на /blog/tags/<the-tag>. Вы можете думать об этом (отказ от ответственности: это не так, как на самом деле работает), когда Wagtail получает запрос на /blog/archives/<the-year>/, этот путь не будет существовать в дереве (и не будет /blog/archives/), но /blog/ делает, поэтому Wagtail загружает вашу страницу для маршрутизации и проверяет маршрут, который будет соответствовать /archives/<the-year> (потому что он уже разрешен /blog/).

Так что, если вы хотите изменить то, что находится до пути к вашей текущей странице, RoutablePageMixin должен быть частью объявления родительской страницы в дереве. Предполагая, что ваши PostPage являются прямыми детьми вашей домашней страницы, вот так:

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/)

Тогда вы включите 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)

Но теперь у вас есть проблема, потому что ваши сообщения технически существуют на 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)

При этом я бы не советовал использовать redirect. Это действительно изгибает трясогузку против ее основных принципов.

Если вы изменили структуру URL-адреса, чтобы она не соответствовала пути дерева Wagtail, вам также следует рассмотреть возможность изменения URL-адресов карты сайта.

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),
            }
        ]
...