#django #join #orm
#django #Присоединиться #orm
Вопрос:
У меня есть таблица узлов и таблица параметров с внешним ключом, связывающим параметры с узлами. Я хочу выбрать все хосты и параметр «kernelversion».
>>> q = Parameter.objects.filter(name__exact='kernelrelease').select_related('host')[:1]
Это SQL-запрос, который, как он показывает, будет использоваться, обратите внимание, что он выбирает все поля из inventory_host, однако в конечном наборе запросов отображаются только столбцы 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 1G
*************************** 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)
Комментарии:
1.
.select_related
элементы не будут.values()
включены..select_related
используется для заполнения объектов для aForeignKey
.2. OP, я рекомендую прочитать документацию django по select_related; он не используется для того, для чего, как вы предполагаете, он используется, поэтому чтение документов поможет прояснить ситуацию.
3. Может кто-нибудь, пожалуйста, помогите мне указать правильный путь для того, какой запрос ORM выдает мне все хосты из таблицы hosts и их значение из таблицы параметров, где «parameter.name = kernelversion»
Ответ №1:
Кажется, запрос Django был правильным, и все данные были там, но .values()
не отображали все это. Если бы я это сделал .values('value', 'host__certname')
, это показало бы 2 столбца, value
из Parameters
таблицы и certname
из Host
таблицы, потому что тогда я говорю Django предоставить мне данные из связанной с FK таблицы.
Как намекнули люди в комментариях к моему вопросу в своих предложениях RTFM, Django автоматически отслеживает все отношения с внешним ключом, поэтому, если у меня есть Parameter -> Host -> Datacenter
, с FK, связывающий их с этой цепочкой, выбор a Parameter
позволяет мне Host
также Datacenter
автоматически получать доступ к значениям из и. Однако при вызове этих значений он выполняет больше SQL-запросов за кулисами, поэтому, чтобы избежать выполнения SQL-запроса для каждой строки, вы можете select_related
получить все значения из этих отношений FK в первом запросе, и он выполняет гораздо меньше запросов.
В результате того, как Django следует за отношениями FK, кажется, что мой запрос не может начинаться с Host, если эта таблица находится в «середине» отношения FK, например Parameter -> Host -> Datacenter
. Для того, чтобы выполнить «обратный» ключ из Host -> Parameter
, вам понадобится _set
, как описано здесь, — обратный поиск связанных объектов