1. 程式人生 > >Django Rest Framework 視圖和路由

Django Rest Framework 視圖和路由

django 內部 initial tro war create edit serialize else

DRF的視圖

APIView

#CBV中的View 與rest_framework中APIView

urlpatterns = [
    url(r^book$, BookView.as_view()),
    url(r^book/(?P<id>\d+)$, BookEditView.as_view()),
]

# 在url中都是調用as_view()方法

在看看源碼中

技術分享圖片

我們能看到,APIView繼承了View, 並且執行了View中的as_view()方法,最後把view返回了,用csrf_exempt()方法包裹後去掉了csrf的認證。

那我們看看View中的as_view()方法做了什麽

技術分享圖片

我們看到了在View中的as_view方法返回了view函數,而view函數執行了self.dispatch()方法但是這裏的dispatch方法應該是我們APIView中的

技術分享圖片

我們去initialize_request中看下把什麽賦值給了request,並且賦值給了self.request, 也就是我們在視圖中用的request.xxx到底是什麽

技術分享圖片

我們看到,這個方法返回的是Request這個類的實例對象我們註意我們看下這個Request類中的第一個參數request,是我們走我們django的時候的原來的request

技術分享圖片

我們看到了,這個Request類把原來的request賦值給了self._request, 也就是說以後_request是我們老的request,新的request是我們這個Request類

那我們繼承APIView之後請求來的數據都在哪呢

技術分享圖片

我們用了rest_framework框架以後,我們的request是重新封裝的Request類

request.query_params 存放的是我們get請求的參數

request.data 存放的是我們所有的數據,包括post請求的以及put,patch請求

相比原來的django的request,我們現在的request更加精簡,清晰了

第一次封裝

技術分享圖片
class BookView(APIView):

    def get(self, request):
        query_set = Book.objects.all()
        book_ser = BookSerializer(query_set, many=True)
        return Response(book_ser.data)

    def post(self, request):
        query_set = request.data
        book_ser = BookSerializer(data=query_set)
        if book_ser.is_valid():
            book_ser.save()
            return Response(book_ser.validated_data)
        else:
            return Response(book_ser.errors)


class BookEditView(APIView):

    def get(self, request, id):
        query_set = Book.objects.filter(id=id).first()
        book_ser = BookSerializer(query_set)
        return Response(book_ser.data)

    def patch(self, request, id):
        query_set = Book.objects.filter(id=id).first()
        book_ser = BookSerializer(query_set, data=request.data, partial=True)
        if book_ser.is_valid():
            book_ser.save()
            return Response(book_ser.validated_data)
        else:
            return Response(book_ser.errors)

    def delete(self, request, id):
        query_set = Book.objects.filter(id=id).first()
        if query_set:
            query_set.delete()
            return Response("")
        else:
            return Response("刪除的書籍不存在")
APIView視圖 技術分享圖片
class GenericAPIView(APIView):
    queryset = None
    serializer_class = None

    def get_queryset(self):
        return self.queryset.all()

    def get_serializer(self, *args, **kwargs):
        return self.serializer_class(*args, **kwargs)


class ListModelMixin(object):
    def list(self, request, *args, **kwargs):
        queryset = self.get_queryset()
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)


class CreateModelMixin(object):
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.validated_data)
        else:
            return Response(serializer.errors)


class RetrieveModelMixin(object):
    def retrieve(self, request, id, *args, **kwargs):
        book_obj = self.get_queryset().filter(pk=id).first()
        book_ser = self.get_serializer(book_obj)
        return Response(book_ser.data)


class UpdateModelMixin(object):
    def update(self, request, id, *args, **kwargs):
        book_obj = self.get_queryset().filter(pk=id).first()
        book_ser = self.get_serializer(book_obj, data=request.data, partial=True)
        if book_ser.is_valid():
            book_ser.save()
            return Response(book_ser.validated_data)
        else:
            return Response(book_ser.errors)


class DestroyModelMixin(object):
    def destroy(self, request, id, *args, **kwargs):
        queryset = self.get_queryset()
        try:
            queryset.get(pk=id).delete()
            return Response("")
        except Exception as e:
            return Response("信息有誤")
# 我們把公共的部分抽出來 這樣不管寫多少表的增刪改查都變的很簡單
# 這樣封裝後我們的視圖會變成這樣

class BookView(GenericAPIView, ListModelMixin, CreateModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)


class BookEditView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request, id, *args, **kwargs):
        return self.retrieve(request, id, *args, **kwargs)

    def patch(self, request, id, *args, **kwargs):
        return self.update(request, id, *args, **kwargs)

    def destroy(self, request, id, *args, **kwargs):
        return self.delete(request, id, *args, **kwargs)
第一次封裝

我們封裝的GenericAPIView,包括封裝每個方法的類,其實框架都幫我們封裝好了

我們可以直接繼承這些類來實現上面的視圖可是還有沒有更簡單的方法呢我們再次封裝一下

第二次封裝

技術分享圖片
# 上面我們寫的繼承類太長了~~我們再改改

class ListCreateAPIView(GenericAPIView, ListModelMixin, CreateModelMixin):
    pass


class RetrieveUpdateDestroyAPIView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
    pass


class BookView(ListCreateAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)


class BookEditView(RetrieveUpdateDestroyAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request, id, *args, **kwargs):
        return self.retrieve(request, id, *args, **kwargs)

    def patch(self, request, id, *args, **kwargs):
        return self.update(request, id, *args, **kwargs)

    def delete(self, request, id, *args, **kwargs):
        return self.delete(request, id, *args, **kwargs)
第二次封裝

這次我們只是讓繼承變的簡單了一點而已,好像並沒有什麽大的進步

我們可不可以把這兩個視圖合並成一個視圖呢框架給我們提供了一個路由傳參的方法

我們看下ViewSetMixin

技術分享圖片

actions這個默認參數其實就是我們路由可以進行傳參了

下面這個循環可以看出我們要傳的參數是一個字段key應該是我們的請求方式,value應該對應我們處理的方法

這樣我們每個視圖就不用在寫函數了因為已經和內部實現的函數相對應了

第三次封裝

技術分享圖片
urlpatterns = [
    # url(r‘^book$‘, BookView.as_view()),
    # url(r‘^book/(?P<id>\d+)$‘, BookEditView.as_view()),
    url(r^book$, BookView.as_view({"get": "list", "post": "create"})),
    url(r^book/(?P<pk>\d+)$, BookView.as_view({"get": "retrieve", "patch": "update", "delete": "destroy"})),
]

路由urls.py
路由urls.py 技術分享圖片
from rest_framework.viewsets import ViewSetMixin


# class BookView(ViewSetMixin, ListCreateAPIView, RetrieveUpdateDestroyAPIView):
#     queryset = Book.objects.all()
#     serializer_class = BookSerializer
    
    
# 如果我們再定義一個類
class ModelViewSet(ViewSetMixin, ListCreateAPIView, RetrieveUpdateDestroyAPIView):
    pass


class BookView(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

第三次封裝
第三次封裝

我們現在的視圖就只要寫兩行就可以了

其實我們寫的所有的視圖框架都幫我們封裝好了

註意一點用框架封裝的視圖我們url上的那個關鍵字參數要用pk系統默認的

奉獻一張圖來看下我們的繼承順序

技術分享圖片

DRF的路由

我們上面的路由傳參寫的特別多框架也幫我們封裝好了

技術分享圖片
from .views import BookView
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register(r"book", BookView)

urlpatterns = [
    # url(r‘^book$‘, BookView.as_view()),
    # url(r‘^book/(?P<id>\d+)$‘, BookEditView.as_view()),
    # url(r‘^book$‘, BookView.as_view({"get": "list", "post": "create"})),
    # url(r‘^book/(?P<pk>\d+)$‘, BookView.as_view({"get": "retrieve", "patch": "update", "delete": "destroy"})),

]
urlpatterns += router.urls

路由
路由

Django Rest Framework 視圖和路由