Wagtail按外键筛选子页

2024-10-04 05:32:37 发布

您现在位置:Python中文网/ 问答频道 /正文

我使用的是Wagtail,我想用外键筛选所选的子页面。我尝试了以下操作,在尝试children = self.get_children().specific().filter(use_case__slug=slug)时出现错误django.core.exceptions.FieldError: Cannot resolve keyword 'use_case' into field

class AiLabResourceMixin(models.Model):
  parent_page_types = ['AiLabResourceIndexPage']
  use_case = models.ForeignKey(AiLabUseCase, on_delete=models.PROTECT)
  content_panels = ArticlePage.content_panels + [
    FieldPanel('use_case', widget=forms.Select())
  ]

  class Meta:
    abstract = True

class AiLabCaseStudy(AiLabResourceMixin, ArticlePage):
  pass

class AiLabBlogPost(AiLabResourceMixin, ArticlePage):
  pass

class AiLabExternalLink(AiLabResourceMixin, ArticlePage):
  pass

class AiLabResourceIndexPage(RoutablePageMixin, BasePage):
  parent_page_types = ['AiLabHomePage']
  subpage_types = ['AiLabCaseStudy', 'AiLabBlogPost', 'AiLabExternalLink']
  max_count = 1

  @route(r'^$')
  def all_resources(self, request):
    children = self.get_children().specific()

    return render(request, 'ai_lab/ai_lab_resource_index_page.html', {
      'page': self,
      'children': children,
    })

  @route(r'^([a-z0-9]+(?:-[a-z0-9]+)*)/$')
  def filter_by_use_case(self, request, slug):
    children = self.get_children().specific().filter(use_case__slug=slug)

    return render(request, 'ai_lab/ai_lab_resource_index_page.html', {
      'page': self,
      'children': children,
    })

我已经看到了this answer,但这假设我只想筛选一种类型的页面。使用类似AiLabCaseStudy.objects.filter(use_case__slug=slug)的方法是可行的,但这只返回AiLabCaseStudys,而不是AiLabBlogPosts或AiLabExternalLinks

有什么想法吗


Tags: selfgetuserequestlabpagefilterai
2条回答

在数据库级别,没有一种有效的方法可以一次针对所有页面类型运行筛选器。由于AiLabResourceMixin被定义为abstract = True,因此该类在数据库中没有自己的表示形式-相反,为AiLabCaseStudyAiLabBlogPostAiLabExternalLink分别定义了use_case字段。因此,Django或Wagtail无法将.filter(use_case__slug=slug)转换为SQL查询,因为use_case引用数据库中的三个不同位置

有几种可能的解决方法:

  • 如果您的数据模型允许,请将其重新构造为使用multi-table inheritance-这看起来与您当前的定义非常相似,只是没有abstract = True

    class AiLabResourcePage(ArticlePage):
      use_case = models.ForeignKey(AiLabUseCase, on_delete=models.PROTECT)
    
    class AiLabCaseStudy(AiLabResourcePage):
      pass
    
    class AiLabBlogPost(AiLabResourcePage):
      pass
    
    class AiLabExternalLink(AiLabResourcePage):
      pass
    

    AiLabResourcePage将以其自身的形式存在于数据库中,并且您可以使用如下表达式查询其use_case字段:AiLabResourcePage.objects.child_of(self).filter(use_case__slug=slug).specific()。这里会有一个小的性能影响,因为Django必须从一个额外的表中提取数据来构造这些页面对象

  • 在使用specific()运行最终查询之前,对每个特定页面类型运行初步查询以检索匹配的页面ID:

    case_study_ids = list(AiLabCaseStudy.objects.child_of(self).filter(use_case__slug=slug).values_list('id', flat=True))
    blog_post_ids = list(AiLabBlogPost.objects.child_of(self).filter(use_case__slug=slug).values_list('id', flat=True))
    external_link_ids = list(AiLabExternalLink.objects.child_of(self).filter(use_case__slug=slug).values_list('id', flat=True))
    children = Page.objects.filter(id__in=(case_study_ids + blog_post_ids + external_link_ids)).specific()
    

尝试:

children = self.get_children().filter(use_case__slug=slug).specific()

相关问题 更多 >