Isaac To
Isaac To

Reputation: 739

Is this use of select_related() beneficial?

In Django's documentation, there is the following example.

>>> b = Blog.objects.get(pk=1)

# Update all the headlines belonging to this Blog.
>>> Entry.objects.select_related().filter(blog=b).update(headline='Everything is the same')

And the example is based on the following definitions of models.

from django.db import models

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

    def __str__(self):
        return self.name

class Author(models.Model):
    name = models.CharField(max_length=200)
    email = models.EmailField()

    def __str__(self):
        return self.name

class Entry(models.Model):
    blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
    headline = models.CharField(max_length=255)
    body_text = models.TextField()
    pub_date = models.DateField()
    mod_date = models.DateField()
    authors = models.ManyToManyField(Author)
    number_of_comments = models.IntegerField()
    number_of_pingbacks = models.IntegerField()
    rating = models.IntegerField()

    def __str__(self):
        return self.headline

What is the benefit of having select_related() in the line of Entry.objects.select_related().filter(blog=b).update(headline='Everything is the same') ?

I don't see any benefit of having select_related() in the update statement. In fact, I think Entry.objects.filter(blog=b).update(headline='Everything is the same') has a better performance for it doesn't perform an unneeded inner join and doesn't populate the unneeded Blog objects.

What do you think?

Upvotes: 2

Views: 45

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477230

I don't see any benefit of having select_related() in the update statement.

Indeed. .select_related(…) [Django-doc] has nothing to do with .filter(…) [Django-doc]. It only means that when you retrieve data, it will already retrieve related objects, and wrap these columns in objects that are accessed through the ForeignKey. It thus is a mechanism to avoid N+1 problems.

But for filtering, annotating, etc. Django will construct a query that makes a join with the necessary tables when used. Here one thus can omit the .select_related(…). This will normally be ignored by the Django ORM, since an UPDATE on a query with JOINs will normally raise exceptions at the database level, since then it is no longer clear how to update this.

Likely this is a copy-paste from the One-to-many relationships sections of the documentation, where we see:

>>> e = Entry.objects.select_related().get(id=2)

Update: I created a ticket for this, and it was fixed in the source code [GitHub]

Upvotes: 1

Related Questions