[英]Prefetching model with GenericForeignKey
I have a data structure in which a Document
has many Blocks
which have exactly one Paragraph
or Header
.我有一个数据结构,其中Document
有许多Blocks
,这些Blocks
正好有一个Paragraph
或Header
。 A simplified implementation:一个简化的实现:
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()
(Note that there is an actual need for having Paragraph
and Header
in separate models unlike in the implementation above.) (请注意,与上面的实现不同,实际上需要在单独的模型中使用Paragraph
和Header
。)
I use jinja2
to template a Latex file for the document.我使用jinja2
为文档模板化一个 Latex 文件。 Templating is slow though as jinja performs a new database query for every Block and Paragraph or Header.尽管 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()
is a function that converts a HTML string to a Latex string) ( content_block.latex_text()
是一个将 HTML 字符串转换为 Latex 字符串的函数)
Hence I would like to prefetch script.blocks
and blocks.content_block
.因此我想预取script.blocks
和blocks.content_block
。 I understand that there are two methods for prefetching in Django:我知道在Django中有两种预取方法:
select_related()
performs a JOIN
query but only works on ForeignKeys
. select_related()
执行JOIN
查询,但仅适用于ForeignKeys
。 It would work for script.blocks
but not for blocks.content_block
.它适用于script.blocks
但不适用于blocks.content_block
。
prefetch_related()
works with GenericForeignKeys as well, but if I understand the docs correctly, it can only fetch one ContentType
at a time while I have two. prefetch_related()
适用于 GenericForeignKeys,但如果我正确理解文档,它一次只能获取一个ContentType
,而我有两个。
Is there any way to perform the necessary prefetching here?有没有办法在这里执行必要的预取? Thank you for your help.感谢您的帮助。
I guess you can prefetch a Generic FK, the problem would arise only if you have another level after generic.我猜你可以预取一个泛型 FK,只有当你在泛型之后有另一个级别时才会出现问题。
Did you try你试过了吗
document = (
Document.objects
.select_related('blocks')
.prefecth_related('blocks__content_block')
)
Does it raise any errors?它会引发任何错误吗? Can you please update your code with the view's code?你能用视图的代码更新你的代码吗?
Not really an elegant solution but you can try using reverse generic relations
:不是一个优雅的解决方案,但您可以尝试使用reverse generic relations
:
from django.contrib.contenttypes.fields import GenericRelation
class Paragraph(models.Model):
text = models.TextField()
blocks = GenericRelation(Block, related_query_name='paragraph')
class Header(models.Model):
text = models.TextField()
level = models.SmallPositiveIntegerField()
blocks = GenericRelation(Block, related_query_name='header')
and prefetch on that:并预取:
Document.objects.prefetch_related('block_set__header', 'block_set__paragraph')
then change the template rendering to something like (not tested, will try to test later):然后将模板渲染更改为类似(未测试,稍后将尝试测试):
\documentclass[a4paper,10pt]{report}
\begin{document}
{% for block in chapter.block_set.all %}
{% if block.header %}
\section{ {{- block.header.0.latex_text -}} }
{% elif block.paragraph %}
{{ block.paragraph.0.latex_text }}
{% endif %}
{% endfor %}
\end{document}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.