# models.py: class Library(models.Model): name = models.CharField(max_length=100) books = models.ManyToManyField(Book) class Book(models.Model): title = models.CharField(max_length=100)
# views.py def myview(request): # Query the database. libraries = Library.objects.all() # Query the database on each iteration (len(author) times) # if there is 100 librairies, there will have 100 queries plus the initial query for library in libraries: books = library.books.all() books[0].title # ... # total : 101 queries
使用prefetch_related上ManyToManyField,如果你知道你需要访问后场是一个ManyToManyField场。
# views.py def myview(request): # Query the database. libraries = Library.objects.prefetch_related('books').all() # Does not query the database again, since `books` is pre-populated for library in libraries: books = library.books.all() books[0].title # ... # total : 2 queries - 1 for libraries, 1 for books
prefetch_related 也可以用于查找字段:
# models.py: class User(models.Model): name = models.CharField(max_length=100) class Library(models.Model): name = models.CharField(max_length=100) books = models.ManyToManyField(Book) class Book(models.Model): title = models.CharField(max_length=100) readers = models.ManyToManyField(User)
# views.py def myview(request): # Query the database. libraries = Library.objects.prefetch_related('books', 'books__readers').all() # Does not query the database again, since `books` and `readers` is pre-populated for library in libraries: for book in library.books.all(): for user in book.readers.all(): user.name # ... # total : 3 queries - 1 for libraries, 1 for books, 1 for readers
但是,一旦执行了查询集,就无法更改获取的数据,而无需再次击中数据库。下面将执行额外的查询,例如:
# views.py def myview(request): # Query the database. libraries = Library.objects.prefetch_related('books').all() for library in libraries: for book in library.books.filter(title__contains="Django"): print(book.name)
可以使用PrefetchDjango 1.7中引入的对象优化以下内容:
from django.db.models import Prefetch # views.py def myview(request): # Query the database. libraries = Library.objects.prefetch_related( Prefetch('books', queryset=Book.objects.filter(title__contains="Django") ).all() for library in libraries: for book in library.books.all(): print(book.name) # Will print only books containing Django for each library