1. 程式人生 > >DjangoRestFramework檢視和路由

DjangoRestFramework檢視和路由

一、restfull規範的簡單介紹

1、介紹

REST:表述性狀態轉移,是一種web互動方案

資源:在web中只要有被引用的必要都是資源

URI:
  URI 統一資源識別符號
  URL 統一資源定位符

統一資源介面
  根據HTTP請求方式的不同對資源進行不同的操作
  遵循HTTP請求方式的語義

前後端傳輸的叫資源的表述

前端展現的叫資源的狀態

通過超連結的指引告訴使用者接下來有哪些資源狀態可以進入

2、restfull規範

核心思想
    -- 面向資源去程式設計
        每個url就是資源的體現 儘量用名詞不要用動詞
    -- 根據HTTP請求方式的不同對資源進行不同的操作

URL體現
    
-- 版本 https://v3.bootcss.com https://bootcss.com/v3 -- 體現是否是API https://v3.bootcss.com/api -- 過濾資訊 https://v3.bootcss.com?page=1 -- 儘量用HTTPS 返回值體現 -- 攜帶狀態碼 -- 攜帶錯誤資訊 -- 返回值 get 返回檢視的所有或者單條資訊 post 返回新增的那條資料 put/patch 返回更新那條資料 delete 返回空
-- 攜帶超連結

 

二、DRF的檢視的封裝

1、為什麼要封裝

當有很多個表進行增刪改查時,實際上很多程式碼都是相同的,只是要獲取的queryset和序列化器等不同,這就導致我們的檢視有特別多重複的程式碼,
因此對檢視進行封裝,可減少程式碼的冗餘。

 

2、要封裝的原檢視

class BookView(APIView):
    def get(self, request):
        book_queryset = Book.objects.all()
        ser_obj = BookSerializer(book_queryset, many=True)
        
return Response(ser_obj.data) # 新增書籍 def post(self, request): book_obj = request.data ser_obj = BookSerializer(data=book_obj) if ser_obj.is_valid(): ser_obj.save() print(ser_obj.validated_data) return Response(ser_obj.data) # 校驗不通過返回錯誤資訊 return Response(ser_obj.errors) # 編輯書籍 class BookEditView(APIView): def get(self, request, id): book_obj = Book.objects.filter(pk=id).first() ser_obj = BookSerializer(book_obj) return Response(ser_obj.data) def put(self, request, id): book_obj = Book.objects.filter(id=id).first() ser_obj = BookSerializer(instance=book_obj, data=request.data, partial=True) if ser_obj.is_valid(): ser_obj.save() return Response(ser_obj.data) return Response(ser_obj.errors) def delete(self, request, id): book_obj = Book.objects.filter(id=id).first() if book_obj: book_obj.delete() return Response('') return Response('刪除物件不存在')
View Code

 

3、第一次封裝

# 獲取query_set和序列化器的類
class GenericAPIView(APIView):
    query_set = None
    serializer_class = None

    def get_queryset(self):
        return self.query_set

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


# 實現get方法的類
# 小知識點:一般Mixin代表的是混合類,單獨繼承ListModelMixin你去哪裡找get_queryset方法
# 因此,其他類繼承Mixin類的時候,還應該多繼承其他的某些類
class ListModelMixin(object):
    def list(self, request):
        queryset = self.get_queryset()
        ser_obj = self.get_serializer(queryset, many=True)
        return Response(ser_obj.data)


# 實現post方法的類
class CreateModelMixin(object):
    def create(self, request):
        # 獲取前端傳過來的資料
        obj = request.data
        # 用序列化器做校驗
        ser_obj = self.get_serializer(data=obj)
        if ser_obj.is_valid():
            # 校驗通過,新增書籍
            ser_obj.save()  # 這裡的save方法會去呼叫序列化器的create方法
            print(ser_obj.validated_data)  # validated_data是通過校驗的資料,也會封裝到data裡面
            return Response(ser_obj.data)
        # 校驗不通過返回錯誤資訊
        return Response(ser_obj.errors)


# 實現編輯的get方法的類
class RetrieveModelMixin(object):
    def retrieve(self, request, id):
        book_obj = self.get_queryset().filter(pk=id).first()
        ser_obj = self.get_serializer(book_obj)
        return Response(ser_obj.data)


# 實現編輯的put方法的類
class UpdateModelMixin(object):
    def update(self, request, id):
        book_obj = self.get_queryset().filter(id=id).first()
        ser_obj = self.get_serializer(instance=book_obj, data=request.data, partial=True)
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.data)
        return Response(ser_obj.errors)


# 實現刪除delete方法的類
class DestroyModelMixin(object):
    def destroy(self, request, id):
        book_obj = self.get_queryset().filter(id=id).first()
        if book_obj:
            book_obj.delete()
            return Response("")
        return Response("刪除的物件不存在")


# 書籍列表
class BookView(GenericAPIView,ListModelMixin, CreateModelMixin):
    query_set = Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request):
        return self.list(request)

    def post(self, request):
        return self.create(request)


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

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

    def put(self, request, id):
        return self.update(request, id)

    def delete(self, request, id):
        return self.destroy(request, id)
View Code

 

4、第二次封裝

由於上面的繼承太長了,因此我們細化一點點,其實就是在第一次封裝的基礎上另外設定一些類來進行了繼承。

# 獲取query_set和序列化器的類
class GenericAPIView(APIView):
    query_set = None
    serializer_class = None

    def get_queryset(self):
        return self.query_set

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


# 實現get方法的類
# 小知識點:一般Mixin代表的是混合類,單獨繼承ListModelMixin你去哪裡找get_queryset方法
# 因此,其他類繼承Mixin類的時候,還應該多繼承其他的某些類
class ListModelMixin(object):
    def list(self, request):
        queryset = self.get_queryset()
        ser_obj = self.get_serializer(queryset, many=True)
        return Response(ser_obj.data)


# 實現post方法的類
class CreateModelMixin(object):
    def create(self, request):
        # 獲取前端傳過來的資料
        obj = request.data
        # 用序列化器做校驗
        ser_obj = self.get_serializer(data=obj)
        if ser_obj.is_valid():
            # 校驗通過,新增書籍
            ser_obj.save()  # 這裡的save方法會去呼叫序列化器的create方法
            print(ser_obj.validated_data)  # validated_data是通過校驗的資料,也會封裝到data裡面
            return Response(ser_obj.data)
        # 校驗不通過返回錯誤資訊
        return Response(ser_obj.errors)


# 實現編輯的get方法的類
class RetrieveModelMixin(object):
    def retrieve(self, request, id):
        book_obj = self.get_queryset().filter(pk=id).first()
        ser_obj = self.get_serializer(book_obj)
        return Response(ser_obj.data)


# 實現編輯的put方法的類
class UpdateModelMixin(object):
    def update(self, request, id):
        book_obj = self.get_queryset().filter(id=id).first()
        ser_obj = self.get_serializer(instance=book_obj, data=request.data, partial=True)
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.data)
        return Response(ser_obj.errors)


# 實現刪除delete方法的類
class DestroyModelMixin(object):
    def destroy(self, request, id):
        book_obj = self.get_queryset().filter(id=id).first()
        if book_obj:
            book_obj.delete()
            return Response("")
        return Response("刪除的物件不存在")


# 繼承上面需要的類,別的類只需繼承這個類即可使用這個類繼承的方法
class ListCreateModelMixin(GenericAPIView,ListModelMixin, CreateModelMixin):
    pass

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


# 書籍列表
class BookView(ListCreateModelMixin):
    query_set = Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request):
        return self.list(request)

    def post(self, request):
        return self.create(request)


class BookEditView(RetrieveUpdateDestroyModelMixin):
    query_set = Book.objects.all()
    serializer_class = BookSerializer

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

    def put(self, request, id):
        return self.update(request, id)

    def delete(self, request, id):
        return self.destroy(request, id)
View Code

 

5、第三次封裝

1. DRF框架的ViewSetMixin類重寫了CBV的as_view方法,使其可以接收引數,路由分發的時候會根據引數進行分發,
繼承了ViewSetMixin的類,它的路由as_view可以傳參

2. urls.py
from django.conf.urls import url
from libsys import views

urlpatterns = [
    url(r'^list/$', views.BookModelView.as_view({"get": "list", "post": "create"})),
    url(r'^retrieve/(?P<id>\d+)/$', views.BookModelView.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),
]


3. 第三次封裝
from rest_framework.viewsets import ViewSetMixin  # 重寫as_view使其可以傳參

# Create your views here.

# 獲取query_set和序列化器的類
class GenericAPIView(APIView):
    query_set = None
    serializer_class = None

    def get_queryset(self):
        return self.query_set

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


# 實現get方法的類
# 小知識點:一般Mixin代表的是混合類,單獨繼承ListModelMixin你去哪裡找get_queryset方法
# 因此,其他類繼承Mixin類的時候,還應該多繼承其他的某些類
class ListModelMixin(object):
    def list(self, request):
        queryset = self.get_queryset()
        ser_obj = self.get_serializer(queryset, many=True)
        return Response(ser_obj.data)


# 實現post方法的類
class CreateModelMixin(object):
    def create(self, request):
        # 獲取前端傳過來的資料
        obj = request.data
        # 用序列化器做校驗
        ser_obj = self.get_serializer(data=obj)
        if ser_obj.is_valid():
            # 校驗通過,新增書籍
            ser_obj.save()  # 這裡的save方法會去呼叫序列化器的create方法
            print(ser_obj.validated_data)  # validated_data是通過校驗的資料,也會封裝到data裡面
            return Response(ser_obj.data)
        # 校驗不通過返回錯誤資訊
        return Response(ser_obj.errors)


# 實現編輯的get方法的類
class RetrieveModelMixin(object):
    def retrieve(self, request, id):
        book_obj = self.get_queryset().filter(pk=id).first()
        ser_obj = self.get_serializer(book_obj)
        return Response(ser_obj.data)


# 實現編輯的put方法的類
class UpdateModelMixin(object):
    def update(self, request, id):
        book_obj = self.get_queryset().filter(id=id).first()
        ser_obj = self.get_serializer(instance=book_obj, data=request.data, partial=True)
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.data)
        return Response(ser_obj.errors)


# 實現刪除delete方法的類
class DestroyModelMixin(object):
    def destroy(self, request, id):
        book_obj = self.get_queryset().filter(id=id).first()
        if book_obj:
            book_obj.delete()
            return Response("")
        return Response("刪除的物件不存在")


# 繼承上面需要的類,別的類只需繼承這個類即可使用這個類繼承的方法
class ListCreateModelMixin(GenericAPIView,ListModelMixin, CreateModelMixin):
    pass

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


# 五合一的檢視
# ViewSetMixin必須在GenericAPIView前面,因為需要ViewSetMixin先做路由的分發
class ModelViewSet(ViewSetMixin, ListCreateModelMixin, RetrieveUpdateDestroyModelMixin):
    pass

class BookModelView(ModelViewSet):
    # 這裡什麼都不用寫了,因為as_view重寫後,某個請求進來會預設去找它對應的方法
    # 這裡找不到,就會去父類中找
    query_set = Book.objects.all()
    serializer_class = BookSerializer
View Code

 

6、使用DRF框架幫我們封裝好的模組

1. 直接使用DRF自帶的ModelViewSet(DRF的ModelViewSet也是繼承了ViewSetMixin和那6個方法的類)
注意:
    DRF中使用queryset,我們自定義的是query_set
    用框架封裝的檢視,我們url上的那個關鍵字引數要用pk,系統預設的

2. urls.py
from django.conf.urls import url
from libsys import views

urlpatterns = [
    url(r'^list/$', views.BookModelView.as_view({"get": "list", "post": "create"})),
    url(r'^retrieve/(?P<pk>\d+)/$', views.BookModelView.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),
]

3. 檢視
from rest_framework.viewsets import ModelViewSet  # 這裡的ModelViewSet是DRF給我們的類

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

 

 7、封裝圖解

三、路由

from rest_framework.routers import DefaultRouter

# 第一步例項化物件
router = DefaultRouter()
# 第二步把路由以及檢視註冊到物件
router.register('list', BookModelView) # 路徑,檢視


urlpatterns += router.urls