你是对的,book.author_id 不会再次访问数据库,外键 ID 存储在 book 中。如果您确实使用 DEBUG=True 设置进入 shell,您可以自行查看:
>>> from django.db import connection
>>> connection.queries
[]
>>> book = Book.objects.get(pk=4)
>>> connection.queries
[{u'sql': u'SELECT "yourapp_book"."id", "yourapp_book"."author_id" FROM "yourapp_book" WHERE "yourapp_book"."id" = 4 ',
u'time': u'0.003'}]
>>> book.author_id
7
>>> connection.queries
[{u'sql': u'SELECT "yourapp_book"."id", "yourapp_book"."author_id" FROM "yourapp_book" WHERE "yourapp_book"."id" = 4 ',
u'time': u'0.003'}]
>>> book.author
<Author: Mark Twain>
>>> connection.queries
[{u'sql': u'SELECT "yourapp_book"."id", "yourapp_book"."author_id" FROM "yourapp_book" WHERE "yourapp_book"."id" = 4 ',
u'time': u'0.003'},
{u'sql': u'SELECT "yourapp_author"."id", "yourapp_author"."name" FROM "yourapp_author" WHERE "yourapp_author"."id" = 7 ',
u'time': u'0.001'}]
connection.queries 列出了在DEBUG 开启时通过 django shell 中的 ORM 发送的所有 SQL 查询。请注意,即使在执行 book.author_id 之后也只进行了一次查询,但是当我们执行 book.author 时进行了第二次查询,因为 django 必须返回数据库以获取要显示的作者姓名。
您可以通过book = Book.objects.select_related('author').get(pk=4) 选择图书来避免第二次数据库查询。
>>> connection.queries
[]
>>> book = Book.objects.select_related('author').get(pk=4)
>>> connection.queries
[{u'sql': u'SELECT "yourapp_book"."id", "yourapp_book"."author_id",
"yourapp_author"."id", "yourapp_author"."name"
FROM "yourapp_book" LEFT OUTER JOIN "yourapp_author" ON
( "yourapp_book"."author_id" = "yourapp_author"."id" ) WHERE "yourapp_book"."id" = 4 ',
u'time': u'0.003'}]
>>> book.author
<Author: Mark Twain>
>>> connection.queries
[{u'sql': u'SELECT "yourapp_book"."id", "yourapp_book"."author_id",
"yourapp_author"."id", "yourapp_author"."name"
FROM "yourapp_book" LEFT OUTER JOIN "yourapp_author" ON
( "yourapp_book"."author_id" = "yourapp_author"."id" ) WHERE "yourapp_book"."id" = 4 ',
u'time': u'0.003'}]
我还应该注意,对于在测试期间调试正在运行的 django 应用程序中实际进行的查询数量,django-debug-toolbar 工具是无价的。