通过多个博客标签索引或过滤 Wagtail 博客文章

问题描述 投票:0回答:3

我使用 Wagtail 的教程创建了一个基本的 Wagtail 博客页面。但是,现在我想在博客页面上创建一个过滤器,允许我通过多个博客标签来索引博客页面。

Wagtail 已经附带了 Django REST Framework 和 Django-Taggit。有没有一种简单的方法可以使用预打包的依赖项在 models.py 和 HTML 模板中创建过滤器?

如果没有,我还可以使用哪些其他方法通过多个博客标签来索引 Wagtail 的博客页面?

from django.db import models

from modelcluster.fields import ParentalKey
from modelcluster.contrib.taggit import ClusterTaggableManager
from taggit.models import TaggedItemBase

from wagtail.core.models import Page, Orderable
from wagtail.core.fields import RichTextField
from wagtail.admin.edit_handlers import FieldPanel, InlinePanel, MultiFieldPanel
from wagtail.images.edit_handlers import ImageChooserPanel
from wagtail.search import index


class BlogIndexPage(Page):
    intro = RichTextField(blank=True)

    def get_context(self, request):
        context = super().get_context(request)
        blogpages = self.get_children().live().order_by('-first_published_at')
        context['blogpages'] = blogpages
        return context


class BlogPageTag(TaggedItemBase):
    content_object = ParentalKey(
        'BlogPage',
        related_name='tagged_items',
        on_delete=models.CASCADE
    )


class BlogPage(Page):
    date = models.DateField("Post date")
    intro = models.CharField(max_length=250)
    body = RichTextField(blank=True)
    tags = ClusterTaggableManager(through=BlogPageTag, blank=True)

    def main_image(self):
        gallery_item = self.gallery_images.first()
        if gallery_item:
            return gallery_item.image
        else:
            return None

    search_fields = Page.search_fields + [
        index.SearchField('intro'),
        index.SearchField('body'),
    ]

    content_panels = Page.content_panels + [
        MultiFieldPanel([
            FieldPanel('date'),
            FieldPanel('tags'),
        ], heading="Blog information"),
        FieldPanel('intro'),
        FieldPanel('body'),
        InlinePanel('gallery_images', label="Gallery images"),
    ]


class BlogTagIndexPage(Page):

    def get_context(self, request):

        # Filter by tag
        tag = request.GET.get('tag')
        blogpages = BlogPage.objects.filter(tags__name=tag)

        # Update template context
        context = super().get_context(request)
        context['blogpages'] = blogpages
        return context


class BlogPageGalleryImage(Orderable):
    page = ParentalKey(BlogPage, on_delete=models.CASCADE, related_name='gallery_images')
    image = models.ForeignKey('wagtailimages.Image', on_delete=models.CASCADE, related_name='+')
    caption = models.CharField(blank=True, max_length=250)

    panels = [
        ImageChooserPanel('image'),
        FieldPanel('caption'),
    ]
python django wagtail
3个回答
6
投票

url 查询字符串参数可能会出现多次。例如:

https://domain.tld/path/to/your/blog_tag_index_page/?tag=foo&tag=bar&tag=ni

从请求中获取多个值的方法是使用

request.GET.getlist('tag')

def get_context(self, request): 
    tags = request.GET.getlist('tag')
    blogpages = BlogPage.objects.filter(tags__name__in=tags)

    # Update template context
    context = super().get_context(request)
    context['blogpages'] = blogpages
    return context

接下来,在前端构建 url。使用方法 get 和复选框创建 from。这些复选框应具有相同的

name="tag"
属性。

<!DOCTYPE html>
<html>
<body>
<form action="." method="get">  
  <label>
      <input type="checkbox" name="tag" value="foo">
      Foo
  </label><br>

  <label>
      <input type="checkbox" name="tag" value="bar">
      Bar
  </label><br>

  <label>
      <input type="checkbox" name="tag" value="ni">
      Ni
  </label><br>

  <input type="submit" value="Submit">
</form>
</body>
</html>

如果您不需要复选框,您可以创建其他一些界面并让 Javascript 更新 url。

当然,将 all_tags 添加到页面上下文并迭代 all_tags 以获得所需的 html。

{% for tag in all_tags %}
   <label>
      <input type="checkbox" name="tag" value="{{ tag }}">
      {{ tag }}
  </label><br>
{% endfor %}

这是未经测试的代码,但理论上它应该可以工作。

快乐编码。


0
投票

首先,您没有使用其余框架。我不知道你为什么提到这一点。

您想在前台过滤还是在后台过滤? 在前面,您可以添加一个按钮添加 ?filter=yyyyy 并且您可以在 get_context 部分捕获该上下文。在那里你可以简单地过滤它。


0
投票

这是我的网站使用的代码,其中包括分页,以防您的博客索引页有很多博客文章。我使用单标签。如果标签是列表,可以相应更新。

from django.core.paginator import Paginator
from django.db.models import Subquery
...

def get_context(self, request):
    # Update context to include only published posts, ordered by reverse-chron
    context = super().get_context(request)
    blogpages = Post.objects.live().order_by('-first_published_at')
    blogpages = self.get_children().live().order_by('-first_published_at')

    tag = request.GET.get('tag', None)
    if tag:
        tag_qs = PostTag.objects.filter(tag__slug__in=[tag])
        blogpages = blogpages.filter(id__in=Subquery(tag_qs.values('content_object_id')))

    blogpages = blogpages.distinct()
    
    cur_page = int(request.GET.get('page', 1))
    pagination = Paginator(blogpages, per_page=settings.PER_PAGE)
    context['pagination'] = pagination
    context['cur_page'] = cur_page
    context['blogpages'] = pagination.page(cur_page)
    return context

这是模板:

<div class="container">

          <div class="row gy-4">

            <h1 >{{ page.title }}</h1>


            <div class="intro">{{ page.intro|richtext }}</div>

            {% for post in blogpages.object_list %}
              <div class="col-4">
                <h2 class="col"><a href="{% pageurl post %}">{{ post.title }}</a></h2>
                  <div class="col text text-muted d-inline-block">{% trans 'Ngày' %}: {{page.last_published_at|date:'d/m/Y'}} {% trans 'bởi'%}: {{page.owner}}</div>
                {{ post.specific.intro|richtext }}
              </div>
            {% endfor %}



          </div>
           <div class="row py-2">
            {% if pagination.num_pages > 1 %}
            <nav aria-label="Page navigation blog">
              <ul class="pagination">

                <li class="page-item">
                  <a class="page-link" href="?{%if cur_page > 1 %}page={{cur_page|add:-1}}{%endif%}" aria-label="Previous">
                    <span aria-hidden="true">&laquo;</span>
                    <span class="sr-only">{% trans 'Trước'%}</span>
                  </a>
                </li>

                {% for pn in pagination.page_range %}
                <li class="page-item {%if pn == cur_page %} active {%endif%}"><a class="page-link" href="?page={{pn}}">{{pn}}</a></li>
                {%endfor%}

                <li class="page-item">
                  <a class="page-link" href="?{%if pagination.num_pages > cur_page %}page={{cur_page|add:1}}{%endif%}" aria-label="Next">
                    <span aria-hidden="true">&raquo;</span>
                    <span class="sr-only">{% trans 'Kế'%}</span>

                  </a>
                </li>
              </ul>
            </nav>
        </div>
        {%endif%}
      </div>
© www.soinside.com 2019 - 2024. All rights reserved.