Django的select_related无效

7 投票
1 回答
7268 浏览
提问于 2025-04-18 08:19

我在使用Django的select_related时遇到了一些奇怪的问题。

Models:
class Publisher(models.Model):
 name = models.CharField(max_length=100)
 class Meta:
      app_label = 'models'
      db_table = 'Publisher'
class Book(models.Model):
 name = models.CharField(max_length=100)
 publisher = models.OneToOneField(Publisher)
 class Meta:
      app_label = 'models'
     db_table = 'Book'

输出结果:

books = Book.objects.select_related('publisher').all()
print books.query
SELECT "Book"."id", "Book"."name", "Book"."publisher_id", "Publisher"."id", "Publisher"."name" FROM "Book" INNER JOIN "Publisher" ON ( "Book"."publisher_id" = "Publisher"."id" )
print books.values()
[{'publisher_id': 1, u'id': 1, 'name': u'rest framework'}]

Django生成的查询是正确的,执行时也能获取到数据。但是返回的值里没有包含出版商的信息。

1 个回答

12

你对 selected_related 的理解有点偏差。根据 django 文档中关于 select_related 的说明

select_related 会返回一个查询集,这个查询集会“跟随”外键关系,在执行查询时会选择额外的相关对象数据。这可以提升性能,虽然会生成一个更复杂的查询,但这意味着后续使用外键关系时就不需要再查询数据库了。

正如你已经发现的,添加 select_related 会让 django 选择相关对象的数据(在这个例子中是 Publisher.idPublisher.name)。不过,all() 方法仍然只会返回一个 Book 的查询集。

这个功能的好处在于,当你访问一本 BookPublisher 时,django 就不需要再次查询数据库来获取 Publisher 的信息:

# Hits the database.
# SELECT "Book"."id", "Book"."name", "Book"."publisher_id" ...
b = Book.objects.get(name='Twilight')

# Hits the database again to get the related Book object.
# SELECT "Publisher"."id", "Publisher"."name" ...
p = b.publisher

这样就只需要两次数据库查询,而使用 select_related 只需要一次:

# Hits the database, but already includes Publisher data in the query
# SELECT "Book"."id", "Book"."name", "Book"."publisher_id", "Publisher"."id", "Publisher"."name" ...
b = Book.objects.select_related('publisher').get(name='Twilight')

# Doesn't hit the database, because b.publisher has been prepopulated
# in the previous query.
p = b.publisher

(这个例子稍微改编自 django 文档中的例子)

撰写回答