title: Can I use prefetch_related to cache filtered querysets?
body: <p>I am using DRF to serialize some related models.  In my toy example below, assume that each author can have a million books.  Clearly doing a db query for all "good" books and then another db query for all "bad" books is inefficient. </p>
  
  <p>This post [<a href="http://ses4j.github.io/2015/11/23/optimizing-slow-django-rest-framework-performance/]" rel="nofollow noreferrer">http://ses4j.github.io/2015/11/23/optimizing-slow-django-rest-framework-performance/]</a> offered some suggestions regarding <code>prefetch_related</code>.  But I found that this only helped when I made subsequent calls to <code>.books.all()</code> rather than <code>.books.filter()</code> as happens in the properties below.</p>
  
  <p>Is there any <em>automatic</em> way in Django to cache the books queryset and <em>not</em> have subsequent filters to it hit the database again?</p>
  
  <p>Here is some code:</p>
  
  <p><strong>models.py:</strong></p>
  
  <pre><code>class Author(models.Model):
    name = models.CharField(max_length=100)
  
    @property
    def good_books(self):
      return self.books.filter(is_good=True)
  
    @property
    def bad_books(self):
      return self.books.filter(is_good=False)
  
  
  class Book(models.Model):
    title = models.CharField(max_length=100)
    is_good = models.BooleanField(default=False)
    author = models.ForeignKey(Author, related_name="books")
  </code></pre>
  
  <p><strong>serializers.py:</strong></p>
  
  <pre><code>class BookSerializer(serializers.ModelSerializer):
    class Meta:
      model = Book
      fields = ("title",)
  
  class AuthorSerializer(serializers.ModelSerializer):
    class Meta:
      model = Author
      fields = ("name", "good_books", "bad_books",)
  
    good_books = BookSerializer(many=True, read_only=True, source="good_books")
    bad_books = BookSerializer(many=True, read_only=True, source="bad_books")
  
    @staticmethod
    def setup_eager_loading(queryset):
      queryset = queryset.prefetch_related("books") 
      return queryset
  </code></pre>
  
  <p><strong>views.py:</strong></p>
  
  <pre><code>class AuthorViewSet(viewsets.ReadOnlyModelViewSet):
    serializer = AuthorSerializer
  
    def get_queryset(self):
      queryset = Author.objects.all()
      queryset = self.get_serializer_class().setup_eager_loading(queryset)
      return queryset
  </code></pre>
  
  <p>Thanks.</p>
  
  <hr>
  
  <p><strong>edit:</strong></p>
  
  <p>Using <code>Prefetch</code>:</p>
  
  <pre><code>@staticmethod
  def setup_eager_loading(queryset):
    queryset = queryset.prefetch_related(
      Prefetch("books", queryset=Book.objects.filter(is_good=True), to_attr="good_books"),
      Prefetch("books", queryset=Book.objects.filter(is_good=False), to_attr="bad_books"),
    )
    return queryset
  </code></pre>
  
  <p>This still gives me extra db hits for the calls to <code>filter</code>.</p>