做完了端點,接下來會把功能部分完成。
這邊會新增一個BookDetailSerializer,在其中除了包含BookSerilizer中的欄位外還會將description的欄位加入,因此獨立做一個 serializer 出來。到 book/serializer.py 中新增:
# ...
class BookDetailSerializer(BookSerializer):
    """Serializer for book detail view."""
    class Meta(BookSerializer.Meta):
        fields = BookSerializer.Meta.fields + ['description']
這邊直接繼承自 BookSerializer,而class Meta也同樣繼承自 BookSerializer。
class Meta的繼承語法比較特別,需要注意。
儲存後到 book/views.py 中修改原本的程式碼並新增:
# ...
class BookViewSet(viewsets.ModelViewSet):
    """View for manage book APIs."""
    serializer_class = serializers.BookDetailSerializer # 這邊改為 BookDetailSerializer
    queryset = Book.objects.all()
    authentication_classes = [TokenAuthentication]
    permission_classes = [IsAuthenticated]
    # ...
    def get_serializer_class(self):
        """Return the serializer class for request."""
        if self.action == 'list':
            return serializers.BookSerializer
        return self.serializer_class
此處的函式會覆寫原本存在於ModelViewSet中的預設函式,並將預設的serializer_class設定為 BookDetailSerializer,因大多操作(如 create, update, delete)都會使用到 Book model 的所有欄位;而當 action 為 list 時才會使用BookSerializer,也就會回傳不包含 description 的所有 Book list。延伸閱讀
除了這個函式之外,創建的函式也需要被覆寫,因為我們想讓創建物件的 user 與 object 產生關聯,而原本預設的創建函式沒有此設定。在BookViewSet的下方再加入此函式:
# ...
class BookViewSet(viewsets.ModelViewSet):
    # ...
    def perform_create(self, serializer):
        """Create a new book."""
        serializer.save(user=self.request.user)
以下幾種情況可能會需要像上面一樣製作另一個獨立的 serializer:
完成後,可以再次啟動伺服器測試看看,所有的端點應該都能回傳正確的回應。
這邊請求的
Request body使用application/json。
如此一來,目前 books API 端點的功能都完成了。在製作只有使用 CRUD 的 API 時使用 viewset 搭配 DefaultRouter 是個相當方便快速的工具。接下來會著手製作圖片的上傳功能,明天見~