Django select_related 查询不会将所有值返回到模板

Posted

技术标签:

【中文标题】Django select_related 查询不会将所有值返回到模板【英文标题】:Django select_related query does not return all values to the template 【发布时间】:2017-08-16 06:27:21 【问题描述】:

我有 2 个模型。来自我正在玩弄的 django 网站的 Characters and CharactersDetails。

CharactersDetails 与 Characters 有外键关系

class CharactersDetails(models.Model):
    character_link = models.ForeignKey(Characters)

在我看来,我正在这样做:

'character_info': CharactersDetails.objects.select_related('character_link').filter(character_link_id=pk)

在我的模板中,我只取回 CharactersDetails 表中的字段。

在 manage.py shell 中,我运行了相同的查询,发现它实际上返回了 CharactersDetails 和 Characters 的字段(这是我想要的),但是当视图获取上下文对象时,它只显示来自的项目CharactersDetails 表。

(looking_for_guild_env)klainn:~/workspace (master) $ python manage.py shell
Python 3.4.3 (default, Nov 17 2016, 01:08:31) 
>>> from players.models import Characters,CharactersDetails
>>> myjunk = CharactersDetails.objects.select_related('character_link').filter(character_link_id=1)
>>> print(myjunk)
<QuerySet [<CharactersDetails: CharactersDetails object>]>
>>> print(myjunk.query)
SELECT "characters_details"."id", "characters_details"."character_link_id", "characters_details"."character_class_id", "characters_details"."character_race_id", "characters_details"."character_level", "characters_details"."character_armory_url", "characters_details"."character_profile_image_url", "characters_details"."character_profile_avatar_url", "characters_details"."character_profile_inset_url", "characters"."id", "characters"."character_owner_id", "characters"."character_name", "characters"."character_realm_id", "characters"."character_faction_id", "characters"."insert_date" FROM "characters_details" INNER JOIN "characters" ON ("characters_details"."character_link_id" = "characters"."id") WHERE "characters_details"."character_link_id" = 1
>>> 

我采用相同的查询并将其粘贴到 manage.py dbshel​​l:

(looking_for_guild_env)klainn:~/workspace (master) $ python manage.py dbshell
sqlite> SELECT "characters_details"."id", "characters_details"."character_link_id", "characters_details"."character_class_id", "characters_details"."character_race_id", "characters_details"."character_level", "characters_details"."character_armory_url", "characters_details"."character_profile_image_url", "characters_details"."character_profile_avatar_url", "characters_details"."character_profile_inset_url", "characters"."id", "characters"."character_owner_id", "characters"."character_name", "characters"."character_realm_id", "characters"."character_faction_id", "characters"."insert_date" FROM "characters_details" INNER JOIN "characters" ON ("characters_details"."character_link_id" = "characters"."id") WHERE "characters_details"."character_link_id" = 1;
1|1|15|7|110|http://us.battle.net/wow/en/character/Stormrage/Peppiwyn/simple|stormrage/219/182881755-profilemain.jpg|stormrage/219/182881755-avatar.jpg|stormrage/219/182881755-inset.jpg|1|3|Peppiwyn|192|0|2017-03-20

我得到所有领域。但是模板没有通过最后 6 个值。当我将 .values() 添加到查询集的末尾然后执行以下操作时,我可以看到这一点:

 character_info 

在我看到的模板中:

<QuerySet ['id': 1, 'character_profile_image_url': 'stormrage/219/182881755-profilemain.jpg', 'character_race_id': 7, 'character_level': 110, 'character_profile_avatar_url': 'stormrage/219/182881755-avatar.jpg', 'character_profile_inset_url': 'stormrage/219/182881755-inset.jpg', 'character_armory_url': 'http://us.battle.net/wow/en/character/Stormrage/Peppiwyn/simple', 'character_link_id': 1, 'character_class_id': 15]>

我做错了什么还是有什么特殊的方法可以从模板中调用这些值?

感谢阅读。

【问题讨论】:

【参考方案1】:

queryset 方法.values() 不会隐式添加所选外键的属性。这是extract of the documentation:

一些值得一提的细微之处:

如果您有一个名为 foo 的字段是 ForeignKey默认的 values() 调用将返回一个名为 foo_id 的字典键,因为这是存储实际值的隐藏模型属性的名称(foo 属性指的是相关模型)。当您调用 values() 并传入字段名称时,您可以传入 foo 或 foo_id 并返回相同的内容(字典键将匹配您传入的字段名称)。

您需要将字段列为 values('character_link__field1', 'character_link__field2'...) 参数...或者只是不使用它并处理 ORM 对象,这将使用在一个查询中检索到的数据。

使用django-debug-toolbar 之类的工具,您可以检查您的请求,以确保在呈现模板时只执行一个 SQL 查询。

【讨论】:

【参考方案2】:

执行select_related('character_link') 不会将属性添加到character_info 实例,它只是使用内部连接同时从数据库中获取character_infocharacter_link

在模板中,您访问character_link 实例 character_info.character_link

如果您使用values(),则必须明确包含来自character_link 的字段:

.values('field1', 'field2', 'character_link__field', ...)

【讨论】:

以上是关于Django select_related 查询不会将所有值返回到模板的主要内容,如果未能解决你的问题,请参考以下文章

django 查询集 select_related 。 values() 重命名键

Django select_related 查询不会将所有值返回到模板

Django框架详细介绍---ORM相关操作---select_related和prefetch_related函数对 QuerySet 查询的优化

django select_related - 何时使用它

迭代 Django 中的相关对象:循环查询集或使用单行 select_related(或 prefetch_related)

转 实例详解Django的 select_related 和 prefetch_related 函数对 QuerySet 查询的优化