2013-08-25 56 views

回答

18

從get_queryset返回的查詢集提供了將通過序列化程序的事件列表,該序列化程序控制着對象如何表示。嘗試在你的書串行器增加一個額外的領域,如:

author_count = serializers.IntegerField(
    source='author_set.count', 
    read_only=True 
) 
6

晚五的解決方案將達到分貝爲每個實例的查詢集,所以如果你有一個大的查詢集,他的解決方案將創造大量的查詢。

我會重寫to_representation您的圖書串行的,它重新使用註釋結果。它看起來像這樣:

class BookSerializer(serializers.ModelSerializer): 
    def to_representation(self, instance): 
     return {'id': instance.pk, 'num_authors': instance.authors__count} 

    class Meta: 
     model = Book 
+5

你能否解釋一下 - 爲什麼Fiver的解決方案會產生很多查詢?我認爲序列化程序字段將在queryset執行後進行處理,這將執行正確的連接/分組? – DmitrySemenov

+0

我用'Field(source ='annotated_field')製作了它' – outoftime

+1

@DmitrySemenov我認爲source參數會引用一個方法而不是變量。我之前在代碼中有「source ='author_set.count'」,但事實證明生成了很多查詢(你可以從調試器中看到它),大多數查詢都重複了,並且調用了count方法。 – Tobias

29

接受的解決方案將返回結果數次的數據庫。對於每個結果,將會對數據庫執行count查詢。

問題是關於向序列化程序添加註釋,這比爲響應中的每個項目執行count查詢更有效。

的一個解決方案:

models.py

class Author(models.Model): 
    name = models.CharField(...) 
    other_stuff = models... 
    ... 

class Book(models.Model): 
    author = models.ForeignKey(Author) 
    title = models.CharField(...) 
    publication_year = models... 
    ... 

serializers.py

class BookSerializer(serializers.ModelSerializer): 
    authors = serializer.IntegerField() 

    class Meta: 
     model = Book 
     fields = ('id', 'title', 'authors') 

views.py

class BookViewSet(viewsets.ModelViewSet): 
    queryset = Book.objects.annotate(authors=Count('author')) 
    serializer_class = BookSerializer 
    ... 

這將使在數據庫中的計數級別,避免t o點擊數據庫檢索返回的Book項目中的每一個的作者數。

+0

您可否詳細說明一下如何使用BookViewSet類創建?我試圖達到相同的結果,但一旦我有ViewSet,我不知道如何使用它。 –

+3

它應該是被接受的答案。 – jrobichaud