<p>这并不能准确地回答您的问题,但我认为这将允许您获得期望的结果:不要担心保留queryset,而是将其转换为列表</p>
<p>对于整个代码库中的每个查询集,这不是您想要做的事情,特别是如果您以后可能希望在查询集上构建并使用其他过滤器、排除项等组合查询集,那么更是如此。但是,当您准备呈现页面时(就像您在这里),这是可以的,因为您将以任何方式对查询集进行评估。你让它发生的时间可能会提前几微秒</p>
<pre><code>class BooksView(APIView):
def get(self, request, author, book=None):
author = get_object_or_404(Author, slug=author)
books = list(author.author_books)
if book:
book = Book.objects.get(id=book)
# TODO: add `book` in front of books QuerySet (and remove duplicated if any)
books = [x for x in books if not x == book] # first remove if dup
books.insert(0, book) # now insert at front
serializer = BooksSerializer(books, many=True)
return Response(serializer.data)
</code></pre>
<h3>编辑1</h3>
<p>BooksSerializer(我怀疑它是BaseSerializer的子类)将在您调用它后立即创建一个列表:</p>
<pre><code> def to_representation(self, data):
"""
List of object instances -> List of dicts of primitive datatypes.
"""
# Dealing with nested relationships, data can be a Manager,
# so, first get a queryset from the Manager if needed
iterable = data.all() if isinstance(data, models.Manager) else data
return [
self.child.to_representation(item) for item in iterable
]
</code></pre>
<p><a href="https://github.com/encode/django-rest-framework/blob/master/rest_framework/serializers.py#L663" rel="nofollow noreferrer">https://github.com/encode/django-rest-framework/blob/master/rest_framework/serializers.py#L663</a></p>
<h3>编辑2</h3>
<p>试试这个怎么样?通过在查询集被计算到列表中之前添加<code>exclude</code>,可以防止O(n)扫描列表以查找并删除应该位于顶部的“主要”书籍</p>
<pre><code>class BooksView(APIView):
def get(self, request, author, book=None):
author = get_object_or_404(Author, slug=author)
books = author.author_books
if book:
book = Book.objects.get(id=book)
# TODO: add `book` in front of books QuerySet (and remove duplicated if any)
# ensure the queryset doesn't include the "main" book
books = books.exclude(book_id=book.id)
# evaluate it into a list just like the BookSerializer will anyhow
books = list(books)
# now insert the "main" book at the front of the list
books.insert(0, book)
serializer = BooksSerializer(books, many=True)
return Response(serializer.data)
</code></pre>