Django如何通过连接获取相关对象?
我的Django如何通过连接获取相关对象?,django,django-models,Django,Django 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 = mo
型号与以下型号类似:
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)
然后在其中一个模板中
有一行:
{% if r.gold_star %}<img src="{% static 'gold-star.png' %}">{% endif %}
由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
如果我选择了稍微不同的策略,那么django
选择了错误的连接类型:
query['article__id__gte'] = 0
reporters = Reporter.objects.filter(**query).select_related()
此代码生成类似的查询,但使用内部联接
而不是所需的左外部联接
:
SELECT
`portal_reporter`.`id`,
...,
FROM
`portal_reporter`
INNER JOIN `portal_article`
ON (`portal_reporter`.`id` = `portal_article`.`reporter_id`)
WHERE
...
尝试注释新字段gold\u star
,如果reporter的文章总浏览量超过100000次,则将其设置为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()
)
)
您可以保持模板代码不变。您可以使用select_related
()在相关表上执行联接
还有一个prefetch_related
(),它使用IN
子句通过额外的查询获取相关对象。文件中对差异进行了解释,但如下所示:
通过创建SQL联接并在select语句中包含相关对象的字段来选择与_相关的工作。因此,select_related将获取同一数据库查询中的相关对象。但是,为了避免跨“多”关系加入会导致更大的结果集,select_related仅限于单值关系-外键和一对一
另一方面,prefetch_-related对每个关系执行单独的查找,并在Python中执行“连接”。这允许它预取多对多和多对一对象,这是使用select_-related无法完成的,此外,select_-related还支持外键和一对一关系。它还支持对GenericRelation和GenericForeignKey的预取,但是,它必须限制为一组相同的结果。例如,仅当查询被限制为一种ContentType时,才支持预取GenericForeignKey引用的对象
当与select_related()
一起使用时,您的方法确实创建了适当的联接,并且django
只向数据库发送一个查询,万岁!无论如何,我只想将这两个表连接起来,因此在
语句时不使用CASE。你能再详细一点吗?你用双下划线做连接。您可以简单地编写以下内容:reporters=Reporter.objects.filter(article\uu total\u views\uu gte=100000)
我可以使用类似这样的内容:filter(article\uu Reporter=Reporter.id)
?我得到。。。不是'DeferredAttribute'
错误。您不能这样做,您必须有一个整数或Reporter
的实例,而不是Reporter.id
,但即使这样也没有意义。你到底想要什么?请看编辑2
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()
)
)