是否可以在 Wagtail 页面中使用 prefetch_related 检索相关的(父页面、子页面)?

Is using prefetch_related to retrieve related (parents, children pages) possible In Wagtail Pages?

我面临的问题是重复的查询数量,这使得在页面模型上使用 get_parent() 或 get_children() 时应用程序变慢。如果父页面有模板中使用的图像文件,它也会增加。

所以我正在寻找一种方法来 prefetch_related 页面而不建立外键关系。

假设我有一个 TvSeries 页面模型和一个剧集页面模型:

class TvSeries(Page):
    name = models.CharField()
    producer = models.CharField()

    subpage_types = ['Episode']
class Episode(Page):
    title = models.CharField()
    number = models.CharField()
    parent_page_types = ['TvSeries']

查询剧集模型需要预取TvSeries!如何减少数据库调用?是否可以使用预取和 select 相关?如果是的话怎么办?如果没有,查询数量增加的解决方案是什么?

prefetch_related 不能用于 parent/child 页面关系,因为它们不使用标准的 Django ForeignKey 关系——相反,Wagtail(和 Treebeard)使用 path 字段来表示树的位置。这使得执行无法使用 ForeignKey 高效完成的查询成为可能,例如获取页面的所有后代(在任何深度)。

需要注意的是 prefetch_related 不是 "free" - 它会为后面的每个关系生成一个额外的查询。 Treebeard 的查询方法通常在效率上等于或优于此 - 例如:

series = TvSeries.objects.get(id=123)
episodes = series.get_children()

将在两个查询中获取 TvSeries 及其所有剧集,就像(假设的)prefetch_related 表达式将:

# fake code, will not work...
series = TvSeries.objects.filter(id=123).prefetch_related('child_pages')

但是,get_children 的一个问题是它只会 return 基本 Page 个实例,因此需要进一步查询才能从 Episode 检索特定字段。您可以通过使用 child_of 来避免这种情况:

series = TvSeries.objects.get(id=123)
episodes = Episode.objects.child_of(series)