首页 > 解决方案 > Django - prefetch_related GenericForeignKey 结果并对它们进行排序

问题描述

我有以下结构,其中从通用模型子类化的内容模块通过“页面模块”模型附加到页面,该模型通过以下方式引用它们GenericForeignKey

class SitePage(models.Model):
    title = models.CharField()
    # [etc..]

class PageModule(models.Model):
    page = models.ForeignKey(SitePage, db_index=True, on_delete=models.CASCADE)
    module_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    module_id = models.PositiveIntegerField()
    module_object = GenericForeignKey("module_type", "module_id")

class CommonModule(models.Model):
    published_time = models.DateTimeField()

class SingleImage(CommonModule):
    title = models.CharField()
    # [etc..]

class Article(CommonModule):
    title = models.CharField()
    # [etc..]

目前,由此填充页面会导致大量 SQL 查询。我想以最高效的数据库方式获取给定页面的所有模块内容(即所有 SingleImage 和 Article 实例)。

我不能直截了当prefetch_related,因为它“必须限制在一组同质的结果”,而且我正在获取多种内容类型。

我可以单独获取每个模块类型:

image_modules = PageModule.objects.filter(page=whatever_page, module_type=ContentType.objects.get_for_model(SingleImage)).prefetch_related('module_object_')
article_modules = PageModule.objects.filter(page=whatever_page, module_type=ContentType.objects.get_for_model(Article)).prefetch_related('module_object')

all_modules = image_modules | article_modules

但我需要对它们进行排序:

all_modules.order_by('module_object__published_time')

我不能因为:

“字段‘module_object’不生成自动反向关系,因此不能用于反向查询”

...而且我认为我不能将推荐GenericRelation字段添加到所有内容模型中,因为那里已经有内容了。

所以......我可以这样做吗?还是我卡住了?

标签: djangodjango-models

解决方案


按照上面评论中的建议,我最终得到了这段代码(从 2012 年开始!),它的查询数量大致减少了一半: https ://gist.github.com/justinfx/3095246

然而,正如我上面提到的,这样做是以创建一些相当低效的WHERE pk IN()查询为代价的,所以我实际上并没有节省太多时间。


推荐阅读