減少 ForeignKey 欄位上的查詢次數(n1 個問題)

問題

Django 查詢集以惰性方式進行評估。例如:

# models.py:
class Author(models.Model):
    name = models.CharField(max_length=100)

class Book(models.Model):
    author = models.ForeignKey(Author, related_name='books')
    title = models.CharField(max_length=100)
# views.py
def myview(request):
    # Query the database
    books = Book.objects.all()

    for book in books:
        # Query the database on each iteration to get author (len(books) times)
        # if there is 100 books, there will have 100 queries plus the initial query
        book.author
        # ...

    # total : 101 queries

上面的程式碼使 django 在資料庫中查詢每本書的作者。這是低效的,最好只有一個查詢。

如果你知道以後需要訪問 ForeignKey 欄位,請在 ForeignKey 上使用 select_related

# views.py
def myview(request):
    # Query the database.
    books = Books.objects.select_related('author').all()
    
    for book in books:
        # Does not query the database again, since `author` is pre-populated
        book.author
        # ...

    # total : 1 query

select_related 也可用於查詢欄位:

# models.py:
class AuthorProfile(models.Model):
    city = models.CharField(max_length=100)

class Author(models.Model):
    name = models.CharField(max_length=100)
    profile = models.OneToOneField(AuthorProfile)

class Book(models.Model):
    author = models.ForeignKey(Author, related_name='books')
    title = models.CharField(max_length=100)    
# views.py
def myview(request):
    books = Book.objects.select_related('author')\
                        .select_related('author__profile').all()
   
    for book in books:
        # Does not query database
        book.author.name
        # or
        book.author.profile.city
        # ...

    # total : 1 query