我的models
与以下内容类似:
class Reporter(models.Model):
def gold_star(self):
return self.article_set.get().total_views >= 100000
class Article(models.Model):
reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE)
total_views = models.IntegerField(default=0, blank=True)
然后在其中一个templates
我有这一行:
{% if r.gold_star %}<img src="{% static 'gold-star.png' %}">{% endif %}
显然django
发送与页面上的记者一样多的查询...理想情况下,这可能只是一个查询,它将按标准和join
适当的文章选择记者。有办法吗?
修改
select_related
和prefetch_related
似乎都不起作用,因为我在Reporter
表上选择然后使用RelatedManager
来访问相关数据在Article
。
换句话说,django
在知道非空queryset
之前不知道要预取的内容。
因为文章只能有一个记者,所以可以将这些表连接在一起,然后将过滤器应用于子查询,我只是无法找到它在{{1}中的完成方式。查询语言。
还有其他选择 - 在django
表格中选择并按Article
字段过滤,但这种方法存在问题。如果我删除了某位记者的所有文章,那么我就无法将该记者列入名单,从Reporter
的角度来看,这样的记者不存在,但记者却在Article
表。
EDIT2
我尝试了人们在评论中建议的内容。以下生成所需的查询:
Reporter
reporters = Reporter.objects.filter(**query).select_related().annotate(
gold_star=Case(
When(article__total_views__gte=0, then=Value(1)),
default=Value(0),
output_field=IntegerField()
)
)
生成的查询:
django
现在我只需要找出一种方法,如何生成类似的查询但没有SELECT
`portal_reporter`.`id`,
...,
CASE WHEN `portal_article`.`total_views` >= 0 THEN 1 ELSE 0 END AS `gold_star`
FROM
`portal_reporter`
LEFT OUTER JOIN `portal_article`
ON (`portal_reporter`.`id` = `portal_article`.`reporter_id`)
WHERE
...
/ Case
语句。
EDIT3
如果我选择略有不同的策略,那么When
会选择错误的联接类型:
django
此代码产生类似的查询但使用query['article__id__gte'] = 0
reporters = Reporter.objects.filter(**query).select_related()
代替所需的INNER JOIN
:
LEFT OUTER JOIN
答案 0 :(得分:1)
您可以使用select_related
(https://docs.djangoproject.com/en/1.11/ref/models/querysets/#select-related)在相关表格上进行联接。
还有prefetch_related
(https://docs.djangoproject.com/en/1.11/ref/models/querysets/#prefetch-related)使用IN
子句通过额外查询获取相关对象。这些差异在文档中有解释,但转载如下:
select_related通过创建SQL连接并在SELECT语句中包含相关对象的字段来工作。因此,select_related在同一数据库查询中获取相关对象。但是,为了避免加入“多”关系会产生更大的结果集,select_related仅限于单值关系 - 外键和一对一。
另一方面,prefetch_related对每个关系进行单独查找,并在Python中进行“加入”。这允许它预取多对多和多对一对象,除了select_related支持的外键和一对一关系之外,这些对象无法使用select_related完成。它还支持预取GenericRelation和GenericForeignKey,但是,它必须限制为一组同类结果。例如,仅当查询限制为一个ContentType时,才支持预取GenericForeignKey引用的对象。
答案 1 :(得分:0)
如果记者有一篇文章超过100000 gold_star
,请尝试注释新字段total_views
并将其设置为1:
from django.db.models import Case, When, Value, IntegerField
reporters = Reporter.objects.annotate(
gold_star=Case(
When(article__total_views__gte=100000, then=Value(1)),
default=Value(0),
output_field=IntegerField()
)
)
您可以保留模板代码。