【问题标题】:Indexing or filtering Wagtail blog posts by MULTIPLE blog tags通过多个博客标签索引或过滤 Wagtail 博客文章
【发布时间】:2020-10-21 09:55:35
【问题描述】:

我使用 Wagtail 的 tutorial 创建了一个基本的 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


    【解决方案1】:

    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 %}
    

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

    编码愉快。

    【讨论】:

      【解决方案2】:

      首先,您没有使用 rest 框架。我不知道你为什么提到这个。

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

      【讨论】:

      • 我目前没有使用rest框架,但正在考虑它。有人告诉我可能有一种方法可以使用 rest 框架来创建过滤器。
      • 我想要前端和管理员的过滤器。您能详细说明一下 ?filter=yyyyy 按钮吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-24
      相关资源
      最近更新 更多