Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django select_related does not work

My django select_related works very weirdly

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'

Output:

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 generates the correct query and data is retrieved when I execute it. But values do not contain Publisher

like image 668
user525717 Avatar asked Jun 02 '14 20:06

user525717


1 Answers

You're slightly misunderstanding how selected_related works. Referring to the django docs on select_related:

select_related returns a QuerySet that will “follow” foreign-key relationships, selecting additional related-object data when it executes its query. This is a performance booster which results in a single more complex query but means later use of foreign-key relationships won’t require database queries.

As you already determined, adding select_related causes django to select the related-object's data (Publisher.id & Publisher.name in this case). However, the all() method will still only return a Book QuerySet.

Where this is useful is when you access a Book's Publisher, django will not need to query the database again for the 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

That's two database queries, whereas the select_related lookup is only one:

# Hits the database, but already includes Publisher data in the query
# SELECT "Book"."id", "Book"."name", "Book"."publisher_id", "Publisher"."id", "Publisher"."name" ...
b = Entry.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

(example is a slight variation on the django docs example)

like image 157
pcoronel Avatar answered Sep 18 '22 01:09

pcoronel