select_related, prefetch_related, ManytoManyField


Models.py
from django.db import models

class Publisher(models.Model):
    name = models.CharField(max_length=300)

    def __str__(self):
        return self.name

class Book(models.Model):
    name = models.CharField(max_length=300)
    price = models.IntegerField(default=0)
    publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)

    class Meta:
        default_related_name = 'books'

    def __str__(self):
        return self.name

class Store(models.Model):
    name = models.CharField(max_length=300)
    books = models.ManyToManyField(Book)

    class Meta:
        default_related_name = 'stores'

    def __str__(self):
        return self.name

select related(正を参照)効果

def book_list():
    
    queryset = Book.objects.all()
    
    books = []
    for book in queryset:
        books.append({'id': book.id, 'name': book.name, 'publisher': book.publisher.name})
        
    return books
Function : book_list
Number of Queries : 101
Finished in : 0.08s
def book_list_select_related():

    queryset = Book.objects.select_related('publisher').all()

    books = []

    for book in queryset:
        books.append({'id': book.id, 'name': book.name, 'publisher': book.publisher.name})

    return books
Function : book_list
Number of Queries : 101
Finished in : 0.08s

プリフェッチ相関(逆参照)エフェクト

@query_debugger
def store_list():

    queryset = Store.objects.all()

    stores = []

    for store in queryset:
        books = [book.name for book in store.books.all()]
        stores.append({'id': store.id, 'name': store.name, 'books': books})

    return stores
Function : store_list
Number of Queries : 11
Finished in : 0.02s
@query_debugger
def store_list_prefetch_related():
  
    queryset = Store.objects.prefetch_related('books')

    stores = []

    for store in queryset:
        books = [book.name for book in store.books.all()]
        stores.append({'id': store.id, 'name': store.name, 'books': books})

    return stores
Function : store_list_expensive_books_prefetch_related
Number of Queries : 12
Finished in : 0.05s
fetch->SQL query文
Model.objects
  .filter(조건절)
  .select_related('정방향_참조_필드')   # 해당 필드를 join해서 가져온다.
  .prefetch_related('역방향_참조_필드') # 해당 필드는 추가쿼리로 가져온다.
select * from 'Model' m
(inner OR left outer) join '정방향_참조_필드' r on m.r_id=r.id 
'where '조건절';
select * from '역방향_참조_필드' where id in ('첫번째 쿼리 결과의 id 리스트');

Manytomanyfield through


Manytomanyfieldは自動的に中間テーブルを作成します.
そのモデルクラスを手動で定義する場合はthroughを使用します.
Bookモデルにマークされている時間を知りたい場合は
class Tag(models.Model):
    name = models.CharField(max_length=100)


class Book(models.Model):
    title = models.CharField(max_length=100)
    tags = models.ManyToManyField(Tag, through='BookTag')


class BookTag(models.Model):
    book = models.ForeignKey(Book, on_delete=models.CASCADE)
    tag = models.ForeignKey(Tag, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)    

    class Meta:
        db_table = '생성된 ManyToMany Table 이름'
modelsfield.完了すると、このフィールドのManytomanyfield中間テーブルオブジェクトにアクセスします.
fieldにはid、from id、to idなどがあります.