Django select_related 不显示所有字段,但原始 SQL 显示
Posted
技术标签:
【中文标题】Django select_related 不显示所有字段,但原始 SQL 显示【英文标题】:Django select_related doesn't show all fields, but raw SQL does 【发布时间】:2020-11-09 21:59:45 【问题描述】:我有一个主机表和一个参数表,外键将参数链接回主机。我想选择所有的主机,以及参数“kernelversion”。
>>> q = Parameter.objects.filter(name__exact='kernelrelease').select_related('host')[:1]
这是它将使用的 SQL 查询,注意它选择了 inventory_host 中的所有字段,但最终的 QuerySet 中只显示了 inventory_parameter 列
>>> print(q.query)
SELECT `inventory_parameter`.`id`, `inventory_parameter`.`name`, `inventory_parameter`.`value`, `inventory_parameter`.`host_id`, `inventory_host`.`id`, `inventory_host`.`certname`, `inventory_host`.`report_timestamp`, `inventory_host`.`role`, `inventory_host`.`ipaddress`, `inventory_host`.`operatingsystemrelease`, `inventory_host`.`manufacturer`, `inventory_host`.`productname`, `inventory_host`.`alive`, `inventory_host`.`datacenter_id` FROM `inventory_parameter` INNER JOIN `inventory_host` ON (`inventory_parameter`.`host_id` = `inventory_host`.`id`) WHERE `inventory_parameter`.`name` = kernelrelease ORDER BY `inventory_parameter`.`name` ASC LIMIT 1
>>> q.values()
<QuerySet ['id': 133376, 'name': 'kernelrelease', 'value': '2.6.32-754.3.5.el6.x86_64', 'host_id': 4061]>
我尝试手动运行上面的 SQL 查询,它提供了它应该提供的所有结果。为什么 django 从输出中删除所有 inventory_host 列?
MariaDB [opstools]> SELECT `inventory_parameter`.`id`, `inventory_parameter`.`name`, `inventory_parameter`.`value`, `inventory_parameter`.`host_id`, `inventory_host`.`id`, `inventory_host`.`certname`, `inventory_host`.`report_timestamp`, `inventory_host`.`role`, `inventory_host`.`ipaddress`, `inventory_host`.`operatingsystemrelease`, `inventory_host`.`manufacturer`, `inventory_host`.`productname`, `inventory_host`.`alive`, `inventory_host`.`datacenter_id` FROM `inventory_parameter` INNER JOIN `inventory_host` ON (`inventory_parameter`.`host_id` = `inventory_host`.`id`) WHERE `inventory_parameter`.`name` = 'kernelrelease' AND host_id = 4061 ORDER BY `inventory_parameter`.`name` ASC LIMIT 1\G
*************************** 1. row ***************************
id: 133376
name: kernelrelease
value: 2.6.32-754.3.5.el6.x86_64
host_id: 4061
id: 4061
certname: myhost001.sub.domain.com
report_timestamp: 2020-10-09 11:12:33.765000
role: qwerty
ipaddress: 10.1.108.53
operatingsystemrelease: 6.10
manufacturer: VMware, Inc.
productname: VMware Virtual Platform
alive: 1
datacenter_id: 3
1 row in set (0.00 sec)
【问题讨论】:
.select_related
项目将不在 .values()
中。 .select_related
用于为 ForeignKey
填充对象。
OP,我建议阅读关于 select_related 的 django 文档;它没有用于您假设的用途,因此阅读文档将有助于澄清。
【参考方案1】:
似乎 Django 查询是正确的,所有数据都在那里,但 .values()
并没有全部显示出来。如果我完成了.values('value', 'host__certname')
,它将显示两列,value
来自Parameters
表和certname
来自Host
表,因为那时我告诉 Django 给我来自 FK 相关表的数据。
正如我的问题中的人在他们的 RTFM 建议中暗示的那样,Django 自动遵循所有外键关系,所以如果我有 Parameter -> Host -> Datacenter
,并且 FK 将它们链接到该链上,选择 Parameter
允许我也可以自动访问来自Host
和Datacenter
的值。但是,当调用这些值时,它会在后台执行更多的 SQL 查询,因此为了避免对每一行进行 SQL 查询,您可以select_related
在第一次查询时从那些 FK 关系中获取所有值,并且它运行很多更少的查询。
由于 Django 遵循 FK 关系的方式,如果该表位于像 Parameter -> Host -> Datacenter
这样的 FK 关系的“中间”,我的查询似乎无法以 Host 开头。为了从Host -> Parameter
执行“反向”键,您需要_set
,如此处所述 - reverse related object lookup
【讨论】:
以上是关于Django select_related 不显示所有字段,但原始 SQL 显示的主要内容,如果未能解决你的问题,请参考以下文章
Django查询优化之select_related和prefetch_related
pythonのdjango select_related 和 prefetch_related()
django: select_related() 在一个已经存在的对象上?
迭代 Django 中的相关对象:循环查询集或使用单行 select_related(或 prefetch_related)