获取Django中的相关对象以及如何对相关模型使用预取
models.py获取Django中的相关对象以及如何对相关模型使用预取,django,django-models,django-queryset,prefetch,django-debug-toolbar,Django,Django Models,Django Queryset,Prefetch,Django Debug Toolbar,models.py class Press(models.Model): created = models.DateTimeField(editable=False) title = models.CharField(max_length=500, blank=True) slug = models.SlugField(max_length=600, blank=True, unique=True) def __str__(self): retu
class Press(models.Model):
created = models.DateTimeField(editable=False)
title = models.CharField(max_length=500, blank=True)
slug = models.SlugField(max_length=600, blank=True, unique=True)
def __str__(self):
return self.title
class Scan(models.Model):
press = models.ForeignKey(Press, related_name='scans', on_delete=models.CASCADE)
created = models.DateTimeField(editable=False)
title = models.CharField(max_length=300, blank=True)
main_scan = models.ImageField(upload_to='press/scans', blank=True)
def __str__(self):
return self.title
views.py
class PressListView(ListView):
model = Press
context_object_name = "press"
template_name = "press.html"
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super().get_context_data(**kwargs)
context['press'] =
Press.objects.prefetch_related(Prefetch('scans',
queryset=Scan.objects.select_related('press')))
return context
我想在网站前端实现的是列出所有的新闻和作为封面图片,每个新闻和图片都希望使用scan
模型中的第一次main\u scan
图像
我知道我可以将models.ImageField
添加到Press
model,但我不想-在管理中,我正在使用连接到Press model的扫描模型中的admin.tablerinline
我知道有关于预回迁的文档,但可能我用错了,而且在模板的前端也做错了
问题是如何使它非常优化,性能最好,只需访问数据库一次
以前我是这样做的,它工作正常,但这会导致15个对象的15个SQL语句重复-通过使用django工具栏,我正在检查它的性能,这是非常低效的
{% for article in press %}
{{ article.title }}<br>
<img src="{{ MEDIA_URL }}{{ article.scans.all.0.main_scan }}" alt="">
{% endfor %}
{%用于新闻稿中的文章%}
{{article.title}}
{%endfor%}
我的目标是通过预回迁或其他方式达到DB一次。下面的代码不起作用,因此views.py是错误的,HTML也是错误的
{% for article in press %}
{{ article.title }}<br>
<img src="{{ MEDIA_URL }}{{ article.scans.main_image }}" alt="">
{% endfor %}
{%用于新闻稿中的文章%}
{{article.title}}
{%endfor%}
更新:
15份副本不见了。使用Prefetch()
使用
Prefetch()
时,应将分配给\u attr
,这是预取对象列表可用的属性名称。当前,多余的查询是访问字段的反向关系的结果,因为您分配了相关的\u name='scans'
如果将属性重命名为类似于scans\u list
,则可以访问预取的相关对象
press = Press.objects.prefetch_related(Prefetch(
'scans',
queryset=Scan.objects.select_related('press'),
to_attr='scans_list'
))
然后在模板中,您将能够执行以下操作:
{% for article in press %}
{{ article.title }}<br>
<img src="{{ MEDIA_URL }}{{ article.scans_list.0.main_scan }}" alt="">
{% endfor %}
{%用于新闻稿中的文章%}
{{article.title}}
{%endfor%}
在您的回答中,您正在循环所有扫描-我要做的是列出所有新闻文章(ListView)每个新闻文章都有标题和一个图像-该图像是该新闻文章的第一次扫描-您正在做的-您列出了所有新闻文章,并且为每个文章列出了所有扫描。prefetch_related()得到了一个意外的关键字参数“to_attr”-得到了此错误(上下文['Press']=Press.objects.prefetch_related(Prefetch('scans',queryset=Scan.objects.select_related('press'))、to_attr='scans_list'))并且在模板中它可能不起作用,您不应该使用[0]-它应该像这样-{article.scans_list.0.main_Scan}而不是这个{{article.scans_list[0].main_Scan}-但首先,如果你能修复第一个错误。@Radek我弄乱了一个括号..现在修复了,因为我怀疑你不能使用:{article.scans_list[0].main_scan}
-必须是这个{article.scans_list.0.main_scan}
-然后你将得到无法解析剩余部分:'[0].main_scan'from'article.scans_list[0].main\u scan'
错误,因此当我将您的更改为{{article.scans\u list.0.main\u scan}}
-它开始工作-谢谢,这是最好的优化方法吗?它将19个查询削减为3个,这很完美,很好奇是否可以做其他事情:)-请修复模板标记,我将标记它已解决。没有问题,来自press模型的其他两个查询也是吗?