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):
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
我想在该站点的前端实现的功能是列出所有Press,并且作为每一个的封面图像,都希望使用main_scan
该Scan
模型中的第一幅图像。
我知道我可以添加models.ImageField
到Press
模型中,但是我不想添加-在我admin.TabularInline
从附加到Press模型的扫描模型中使用的管理中。
我知道有关于预取的文档,但是可能我在模板中的前端使用了错误的代码以及使用错误的代码。
问题是如何使其非常优化,以使其性能最佳,只需一次访问数据库。
以前我是这样做的,但确实有效,但是这导致15个对象的15条重复SQL语句-通过使用django-toolbar我正在检查它的性能非常低效。
{% for article in press %}
{{ article.title }}<br>
<img src="{{ MEDIA_URL }}{{ article.scans.all.0.main_scan }}" alt="">
{% endfor %}
我的目标是通过预取或其他方式访问数据库一次。下面的代码无效,因此views.py错误,HTML也是如此。
{% for article in press %}
{{ article.title }}<br>
<img src="{{ MEDIA_URL }}{{ article.scans.main_image }}" alt="">
{% endfor %}
更新:15重复不见了。使用优化后的3个查询Prefetch()
使用时Prefetch()
,应分配一个to_attr
属性名称,预取对象列表将在该属性名称下可用。当前,多余的查询是press
由于您分配了访问字段反向关系的结果related_name='scans'
。
如果将属性重命名为,则可以访问预取的相关对象scans_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 %}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句