【发布时间】:2021-12-08 08:50:50
【问题描述】:
我有一个数据结构,其中Document 有许多Blocks,而其中恰好有一个Paragraph 或Header。一个简化的实现:
class Document(models.Model):
title = models.CharField()
class Block(models.Model):
document = models.ForeignKey(to=Document)
content_block_type = models.ForeignKey(to=ContentType)
content_block_id = models.CharField()
content_block = GenericForeignKey(
ct_field="content_block_type",
fk_field="content_block_id",
)
class Paragraph(models.Model):
text = models.TextField()
class Header(models.Model):
text = models.TextField()
level = models.SmallPositiveIntegerField()
(请注意,与上面的实现不同,Paragraph 和 Header 确实需要在不同的模型中。)
我使用jinja2 为文档制作一个 Latex 文件模板。尽管 jinja 为每个块和段落或标题执行新的数据库查询,但模板化速度很慢。
template = get_template(template_name="latex_templates/document.tex", using="tex")
return template.render(context={'script': self.script})
\documentclass[a4paper,10pt]{report}
\begin{document}
{% for block in chapter.block_set.all() %}
{% if block.content_block_type.name == 'header' %}
\section{ {{- block.content_block.latex_text -}} }
{% elif block.content_block_type.name == 'paragraph' %}
{{ block.content_block.latex_text }}
{% endif %}
{% endfor %}
\end{document}
(content_block.latex_text()是一个将HTML字符串转换为Latex字符串的函数)
因此我想预取script.blocks 和blocks.content_block。我知道在 Django 中有两种预取方法:
-
select_related()执行JOIN查询,但仅适用于ForeignKeys。它适用于script.blocks,但不适用于blocks.content_block。 -
prefetch_related()也适用于 GenericForeignKeys,但如果我正确理解文档,它一次只能获取一个ContentType,而我有两个。
有没有办法在这里执行必要的预取?感谢您的帮助。
【问题讨论】:
-
我认为
Reverse generic relations可能会有所帮助。您可以在Paragraph和Header中定义这些,并为两者添加单独的预取 -
感谢您的评论。我确实看到了反向泛型关系如何提供帮助,但是多个预取甚至看起来像一个查询呢?
-
如果可能的话,你能否分享一下你是如何渲染
script的? -
感谢您没有放弃这一点。我在上面添加了模板。
-
如何将多个预取视为查询? - 预取是在 Python 中完成的,而不是通过 JOIN。所以它会触发多个查询,一个用于主模型,一个用于预取模型
标签: django django-models django-templates django-queryset django-generic-relations