天天看點

Python進階41-drf架構(三)

  • 視圖類傳遞參數給序列化類
  • 二次封裝Response
  • 視圖家族簡介
    • generics APIView視圖基類
    • mixins視圖六大工具類
    • generic中的工具視圖
    • 視圖集viewsets
    • ModelViewSet擁有六大接口
    • 總結
    • 路由元件(了解)
-曾老濕, 江湖人稱曾老大。

-多年網際網路運維工作經驗,曾負責過大規模叢集架構自動化運維管理工作。

-擅長Web叢集架構與自動化運維,曾負責國内某大型金融公司運維工作。

-devops項目經理兼DBA。

-開發過一套自動化運維平台(功能如下):

1)整合了各個公有雲API,自主建立雲主機。

2)ELK自動化收集日志功能。

3)Saltstack自動化運維統一配置管理工具。

4)Git、Jenkins自動化代碼上線及自動化測試平台。

5)堡壘機,連接配接Linux、Windows平台及日志審計。

6)SQL執行及審批流程。

7)慢查詢日志分析web界面。

視圖類傳遞參數給序列化類

介紹
# 1)在視圖類中執行個體化序列化對象時,可以設定context内容
# 2)在序列化類中的局部鈎子、全局鈎子、create、update方法中,都可以用self.context通路視圖類傳遞過來的内容


# 需求:
# 1) 在視圖類中,可以通過request得到登陸使用者request.user
# 2) 在序列化類中,要完成資料庫資料的校驗與入庫操作,可能會需要知道目前的登陸使用者,但序列化類無法通路request
# 3) 在視圖類中執行個體化序列化對象時,将request對象傳遞進去           

複制

視圖層
class Book(APIView):
    def post(self, request, *args, **kwargs):
        book_ser = serializers.BookModelSerializer(data=request_data,context={'request':request})
        book_ser.is_valid(raise_exception=True)
        book_result = book_ser.save()
        return Response({
            'status': 0,
            'msg': 'ok',
            'results': serializers.BookModelSerializer(book_result).data
        })           

複制

序列化層
class BookModelSerializer(ModelSerializer):
    class Meta:
        model = models.Book
        fields = ('name', 'price')
    def validate_name(self, value):
        print(self.context.get('request').method)
        return value           

複制

二次封裝Response

我們之前在寫視圖的時候,發現寫了大量的Response資訊,反複寫,反複寫,重複代碼,如下:

return Response({
    'status': 1,
    'msg': '資料有誤'
    })

return Response({
    'status': 0,
    'msg': 'put OK',
    'results': serializers.V2BookModelSerializer(book_obj).data
    })           

複制

封裝

我們在項目目錄下新建立一個目錄:utils

然後再utils中建立response.py檔案

Python進階41-drf架構(三)

from rest_framework.response import Response

"""
Response({
    'status':0,
    'msg':'ok',
    'results':[],
    'token':'', # 有 這樣的額外的key-value資料結果
},status=http_status,headers=headers,exceptio=True|False)


## 我們想要的結果,就是在APIResponse上加上括号就出來最簡單的結果
APIResponse() => Respone({'status':0, 'msg':'ok',})
"""


class APIResponse(Response):
    def __init__(self, data_status=0, data_msg='ok', results=None, http_status=None, headers=None, exception=False,
                 **kwargs):
        data = {
            'status': data_status,
            'msg': data_msg
        }

        ## results可能是False、0等資料,這些資料某些情況下,也會作為合法資料傳回
        if results is not None:
            data['results'] = results

        if kwargs is not None:
            for k, v in kwargs.items():
                setattr(data, k, v)  ## 反射,相當于:data[k] = v
        super().__init__(data=data, status=http_status, headers=headers, exception=exception)           

複制

測試
from rest_framework.views import APIView
from rest_framework.response import Response

from . import models, serializers
## 導入
from utils.response import APIResponse

class V2Book(APIView):
    # 單查:有pk
    # 群查:無pk
    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if pk:
            try:
                book_obj = models.Book.objects.get(pk=pk, is_delete=False)
                book_data = serializers.V2BookModelSerializer(book_obj).data
            except:
                return Response({
                    'status': 1,
                    'msg': '書籍不存在'
                })
        else:
            book_query = models.Book.objects.filter(is_delete=False).all()
            book_data = serializers.V2BookModelSerializer(book_query, many=True).data
        return Response({
            'status': 0,
            'msg': 'ok',
            'results': book_data
        })

    # 單增:傳的資料是與model對應的字典
    # 群增:傳的資料是 裝多個 model對應字典 的清單
    def post(self, request, *args, **kwargs):
        request_data = request.data
        if isinstance(request_data, dict):
            many = False
        elif isinstance(request_data, list):
            many = True
        else:
            return Response({
                'status': 1,
                'msg': '資料有誤',
            })
        book_ser = serializers.V2BookModelSerializer(data=request_data, many=many)
        # 當校驗失敗,馬上終止目前視圖方法,抛異常傳回給前台
        book_ser.is_valid(raise_exception=True)
        book_result = book_ser.save()
        return Response({
            'status': 0,
            'msg': 'ok',
            'results': serializers.V2BookModelSerializer(book_result, many=many).data
        })

    # 單删:有pk
    # 群删:有pks   |  {"pks": [1, 2, 3]}
    def delete(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if pk:
            pks = [pk]
        else:
            pks = request.data.get('pks')
        if models.Book.objects.filter(pk__in=pks, is_delete=False).update(is_delete=True):
            return Response({
                'status': 0,
                'msg': '删除成功',
            })
        return Response({
            'status': 1,
            'msg': '删除失敗',
        })

    # 單整體改,傳的資料是與model對應的字典{name|price|publish|authors}
    def put(self, request, *args, **kwargs):
        request_data = request.data
        pk = kwargs.get('pk')
        old_book_obj = models.Book.objects.filter(pk=pk).first()
        ## 将衆多 資料的校驗交給序列化類來 處理,讓序列化累扮演反序列化的角色,校驗成功後,序列化幫你入庫
        book_ser = serializers.V2BookModelSerializer(instance=old_book_obj, data=request_data)
        book_ser.is_valid(raise_exception=True)
        # 校驗通過,完成資料的更新:要知道更新的目标,用來更新的新資料
        book_obj = book_ser.save()
        return Response({
            'status': 0,
            'msg': 'put OK',
            'results': serializers.V2BookModelSerializer(book_obj).data
        })

    # 單局部改
    def patch(self, request, *args, **kwargs):
        request_data = request.data
        pk = kwargs.get('pk')
        ## 将單改群改的資料都格式化成pks=[需要修改的對象主鍵辨別] | request_data = [每個要修改對象對應的的修改資料]
        if pk and isinstance(request_data, dict):  # 單改
            pks = [pk, ]
            request_data = [request_data, ]
        elif not pk and isinstance(request_data, list):  # 群改
            pks = []
            for dic in request_data:
                pk = dic.pop('pk', None)
                if pk:
                    pks.append(pk)
                else:
                    return Response({
                        'status': 1,
                        'msg': '資料有誤'
                    })
        else:
            return Response({
                'status': 1,
                'msg': '資料有誤'
            })
        # 将不能操作的資料 剔除 pks與request_data資料篩選
        objs = []
        new_request_data = []
        for index, pk in enumerate(pks):
            try:
                ## pk對應的資料合理,将合理的對象存儲
                obj = models.Book.objects.get(pk=pk, is_delete=False)
                objs.append(obj)
                new_request_data.append(request_data[index])
            except:
                # pk對應的資料有誤,将對應索引的data中request_data中移除
                # index = pks.index(pk)
                # request_data.pop(index)
                continue

        book_ser = serializers.V2BookModelSerializer(instance=objs, data=new_request_data, partial=True, many=True)
        book_ser.is_valid(raise_exception=True)
        # 校驗通過,完成資料的更新:要知道更新的目标,用來更新的新資料
        book_objs = book_ser.save()
        book_objs_data = serializers.V2BookModelSerializer(book_objs, many=True).data
        return APIResponse(results=book_objs_data)           

複制

Python進階41-drf架構(三)

視圖家族簡介

介紹
"""
views:視圖
generics:工具視圖
mixins:視圖工具集
viewsets:視圖集
"""


"""
學習曲線
APIView => GenericAPIView => mixins的五大工具類 => generics中的工具視圖 => viewsets中的視圖集
"""           

複制

generics APIView視圖基類

先把之前序列化的東西儲存下來,然後清空views檔案,我們要開始學習視圖了。

Python進階41-drf架構(三)

路由
from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^v1/books/$', views.BookAPIView.as_view()),
    url(r'^v1/books/(?P<pk>.*)/$', views.BookAPIView.as_view()),

    url(r'^v2/books/$', views.BookGenericAPIView.as_view()),
    url(r'^v2/books/(?P<pk>.*)/$', views.BookGenericAPIView.as_view()),
]           

複制

序列化
from rest_framework.serializers import ModelSerializer, SerializerMethodField
from rest_framework.exceptions import ValidationError
from . import models
from rest_framework.serializers import ListSerializer


class BookListSerializer(ListSerializer):
    def update(self, instance, validated_data):
        for index, obj in enumerate(instance):
            self.child.update(obj, validated_data[index])
        return instance


class BookModelSerializer(ModelSerializer):
    class Meta:
        model = models.Book
        fields = ('name', 'price', 'img', 'author_list', 'publish_name', 'publish', 'authors')
        extra_kwargs = {
            'name': {
                'required': True,
                'min_length': 1,
                'error_messages': {
                    'required': '必填項',
                    'min_length': '太短',
                }
            },
            'publish': {
                'write_only': True
            },
            'authors': {
                'write_only': True
            },
            'img': {
                'read_only': True,
            },
            'author_list': {
                'read_only': True,
            },
            'publish_name': {
                'read_only': True,
            }
        }
        list_serializer_class = BookListSerializer

    def validate_name(self, value):
        if 'g' in value.lower():
            raise ValidationError('該g書不能出版')
        return value

    def validate(self, attrs):
        publish = attrs.get('publish')
        name = attrs.get('name')
        if models.Book.objects.filter(name=name, publish=publish):
            raise ValidationError({'book': '該書已存在'})
        return attrs           

複制

APIView視圖
from rest_framework.views import APIView
from utils.response import APIResponse
from . import models, serializers


class BookAPIView(APIView):
    def get(self, request, *args, **kwargs):
        book_query = models.Book.objects.filter(is_delete=False).all()
        book_ser = serializers.BookModelSerializer(book_query, many=True)
        book_data = book_ser.data
        return APIResponse(results=book_data)           

複制

Python進階41-drf架構(三)

GenericAPIView視圖
from rest_framework.views import APIView
from utils.response import APIResponse
from . import models, serializers
## GenericAPIView 是繼承APIView的 ,完全相容APIView
from rest_framework.generics import GenericAPIView


class BookGenericAPIView(GenericAPIView):
    def get(self, request, *args, **kwargs):
        book_query = models.Book.objects.filter(is_delete=False).all()
        book_ser = serializers.BookModelSerializer(book_query, many=True)
        book_data = book_ser.data
        return APIResponse(results=book_data)           

複制

Python進階41-drf架構(三)

代碼沒有改變,結果完全一樣。

GenericAPIView視圖對比APIView

重點:GenericAPIView在APIView的基礎上完成了哪些事?

1.get_queryset()

2.get_object()

3.get_serializer()

修改代碼如下:

from rest_framework.views import APIView
from utils.response import APIResponse
from . import models, serializers

## GenericAPIView 是繼承APIView的 ,完全相容APIView
from rest_framework.generics import GenericAPIView

### 群取
class BookGenericAPIView(GenericAPIView):
    queryset = models.Book.objects.filter(is_delete=False).all()
    serializer_class = serializers.BookModelSerializer

    def get(self, request, *args, **kwargs):
        book_query = self.get_queryset()
        book_ser = self.get_serializer(book_query, many=True)
        book_data = book_ser.data
        return APIResponse(results=book_data)           

複制

我擦,本來的4步,變成了6步。

from rest_framework.views import APIView
from utils.response import APIResponse
from . import models, serializers

## GenericAPIView 是繼承APIView的 ,完全相容APIView
from rest_framework.generics import GenericAPIView


class BookGenericAPIView(GenericAPIView):
    queryset = models.Book.objects.filter(is_delete=False).all()
    serializer_class = serializers.BookModelSerializer

## 單取
    def get(self, request, *args, **kwargs):
        book_query = self.get_object()
        book_ser = self.get_serializer(book_query)
        book_data = book_ser.data
        return APIResponse(results=book_data)           

複制

Python進階41-drf架構(三)

單取的路由,有名分組,必須叫pk,否則就會報錯

<api.views.BookGenericAPIView object at 0x112135470> - GET - Expected view BookGenericAPIView to be called with a URL keyword argument named "pk". Fix your URL conf, or set the `.lookup_field` attribute on the view correctly.           

複制

總結:

1.get_queryset():從類屬性queryset中獲得model的queryset資料

2.get_object():從類屬性queryset中獲得model的queryset資料,再通過有名分組pk确定唯一操作對象

當然也可以自定義主鍵的有名分組名稱

lookup_field = 'id'

3.get_serializer():從類屬性serializer_class中獲得serializer的序列化類

單取,群取合并
from rest_framework.views import APIView
from utils.response import APIResponse
from . import models, serializers


class BookAPIView(APIView):
    def get(self, request, *args, **kwargs):
        book_query = models.Book.objects.filter(is_delete=False).all()
        book_ser = serializers.BookModelSerializer(book_query, many=True)
        book_data = book_ser.data
        return APIResponse(results=book_data)

## GenericAPIView 是繼承APIView的 ,完全相容APIView
from rest_framework.generics import GenericAPIView


class BookGenericAPIView(GenericAPIView):
    queryset = models.Book.objects.filter(is_delete=False).all()
    serializer_class = serializers.BookModelSerializer

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

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

    def list(self, request, *args, **kwargs):
        book_query = self.get_queryset()
        book_ser = self.get_serializer(book_query,many=True)
        book_data = book_ser.data
        return APIResponse(results=book_data)

    def retrieve(self, request, *args, **kwargs):
        book_query = self.get_object()
        book_ser = self.get_serializer(book_query)
        book_data = book_ser.data
        return APIResponse(results=book_data)           

複制

上面的代碼能看懂,就看,看不懂也不要緊...不要'緊'的,為啥呢?因為别人幫我們幹了...

mixins視圖六大工具類

路由
from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^v1/books/$', views.BookAPIView.as_view()),
    url(r'^v1/books/(?P<pk>.*)/$', views.BookAPIView.as_view()),

    url(r'^v2/books/$', views.BookGenericAPIView.as_view()),
    url(r'^v2/books/(?P<pk>.*)/$', views.BookGenericAPIView.as_view()),

    url(r'^v3/books/$', views.BookListGenericAPIView.as_view()),
    url(r'^v3/books/(?P<pk>.*)/$', views.BookListGenericAPIView.as_view()),
]           

複制

視圖
from rest_framework.views import APIView
from utils.response import APIResponse
from . import models, serializers
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import ListModelMixin


class BookListGenericAPIView(ListModelMixin, GenericAPIView):
    queryset = models.Book.objects.filter(is_delete=False)
    serializer_class = serializers.BookModelSerializer

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

複制

Python進階41-drf架構(三)

使用自定義的APIresponse
class BookListGenericAPIView(ListModelMixin, GenericAPIView):
    queryset = models.Book.objects.filter(is_delete=False)
    serializer_class = serializers.BookModelSerializer

    ## 群查
    def get(self, request, *args, **kwargs):
        response = self.list(request, *args, **kwargs)
        return APIResponse(results=response.data)           

複制

Python進階41-drf架構(三)

實作增加方法

修改一下路由名稱

from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^v1/books/$', views.BookAPIView.as_view()),
    url(r'^v1/books/(?P<pk>.*)/$', views.BookAPIView.as_view()),

    url(r'^v2/books/$', views.BookGenericAPIView.as_view()),
    url(r'^v2/books/(?P<pk>.*)/$', views.BookGenericAPIView.as_view()),

    url(r'^v3/books/$', views.BookMixinGenericAPIView.as_view()),
    url(r'^v3/books/(?P<pk>.*)/$', views.BookMixinGenericAPIView.as_view()),
]           

複制

修改方法名,添加增加方法

class BookMixinGenericAPIView(ListModelMixin, CreateModelMixin, GenericAPIView):
    queryset = models.Book.objects.filter(is_delete=False)
    serializer_class = serializers.BookModelSerializer

    ## 群查
    def get(self, request, *args, **kwargs):
        response = self.list(request, *args, **kwargs)
        return APIResponse(results=response.data)

    def post(self, request, *args, **kwargs):
        response = self.create(request, *args, **kwargs)
        return APIResponse(results=response.data)           

複制

Python進階41-drf架構(三)

單查群查放一起
from rest_framework.views import APIView
from utils.response import APIResponse
from . import models, serializers
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import ListModelMixin, CreateModelMixin, RetrieveModelMixin


class BookMixinGenericAPIView(ListModelMixin, CreateModelMixin, RetrieveModelMixin, GenericAPIView):
    queryset = models.Book.objects.filter(is_delete=False)
    serializer_class = serializers.BookModelSerializer

    ## 群查
    def get(self, request, *args, **kwargs):
        if 'pk' in kwargs:
            response = self.retrieve(request, *args, **kwargs)
        else:
            response = self.list(request, *args, **kwargs)

        return APIResponse(results=response.data)

    def post(self, request, *args, **kwargs):
        response = self.create(request, *args, **kwargs)
        return APIResponse(results=response.data)           

複制

Python進階41-drf架構(三)

Python進階41-drf架構(三)

單改,群改
from rest_framework.mixins import ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin


class BookMixinGenericAPIView(ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, GenericAPIView):
    queryset = models.Book.objects.filter(is_delete=False)
    serializer_class = serializers.BookModelSerializer

    ## 查詢
    def get(self, request, *args, **kwargs):
        if 'pk' in kwargs:
            ## 單查
            response = self.retrieve(request, *args, **kwargs)
        else:
            ## 群查
            response = self.list(request, *args, **kwargs)

        return APIResponse(results=response.data)
    
    ## 增加
    def post(self, request, *args, **kwargs):
        ## 單增
        response = self.create(request, *args, **kwargs)
        return APIResponse(results=response.data)

    ## 修改
    def put(self, request, *args, **kwargs):
        ## 單改
        response = self.update(request, *args, **kwargs)
        return APIResponse(results=response.data)

        ## 群改
    def patch(self, request, *args, **kwargs):
        response = self.partial_update(request, *args, **kwargs)
        return APIResponse(results=response.data)           

複制

generic中的工具視圖

我們學了 Generic 視圖

然後學了 Mixins 工具

接下來學習内容是drf中Generic結合了Mixins,工具視圖

群查單增,路由
from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^v1/books/$', views.BookAPIView.as_view()),
    url(r'^v1/books/(?P<pk>.*)/$', views.BookAPIView.as_view()),

    url(r'^v2/books/$', views.BookGenericAPIView.as_view()),
    url(r'^v2/books/(?P<pk>.*)/$', views.BookGenericAPIView.as_view()),

    url(r'^v3/books/$', views.BookMixinGenericAPIView.as_view()),
    url(r'^v3/books/(?P<pk>.*)/$', views.BookMixinGenericAPIView.as_view()),

    url(r'^v4/books/$', views.BookListCreateAPIView.as_view()),
    url(r'^v4/books/(?P<pk>.*)/$', views.BookListCreateAPIView.as_view()),
]           

複制

群查單增,視圖
from rest_framework.generics import ListCreateAPIView

class BookListCreateAPIView(ListCreateAPIView):
    queryset = models.Book.objects.filter(is_delete=False)
    serializer_class = serializers.BookModelSerializer           

複制

四句話,完成群查和單增...

Python進階41-drf架構(三)

Python進階41-drf架構(三)

如果想要加上修改方法,不需要單獨寫,同樣繼承一下即可,還是4句話

from rest_framework.generics import ListCreateAPIView, UpdateAPIView


class BookListCreateAPIView(ListCreateAPIView, UpdateAPIView):
    queryset = models.Book.objects.filter(is_delete=False)
    serializer_class = serializers.BookModelSerializer           

複制

Python進階41-drf架構(三)

Python進階41-drf架構(三)

視圖集viewsets

重寫了 as_view

視圖
from rest_framework.views import APIView
from utils.response import APIResponse
from . import models, serializers
from rest_framework.generics import GenericAPIView
from rest_framework.generics import ListCreateAPIView, UpdateAPIView


class BookListCreateAPIView(ListCreateAPIView, UpdateAPIView):
    queryset = models.Book.objects.filter(is_delete=False)
    serializer_class = serializers.BookModelSerializer
    
from rest_framework.viewsets import GenericViewSet
class BookGenericViewSet(GenericViewSet):
    queryset = models.Book.objects.filter(is_delete=False)
    serializer_class = serializers.BookModelSerializer
    ## 假裝是群查
    def my_get_list(self, request, *args, **kwargs):
        return APIResponse(0,'假裝這是群查,走到這肯定是成功了')

    ## 假裝是單查
    def my_get_obj(self, request, *args, **kwargs):
        return APIResponse(0, '假裝這是單查,走到這肯定是成功了')           

複制

路由
from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^v1/books/$', views.BookAPIView.as_view()),
    url(r'^v1/books/(?P<pk>.*)/$', views.BookAPIView.as_view()),

    url(r'^v2/books/$', views.BookGenericAPIView.as_view()),
    url(r'^v2/books/(?P<pk>.*)/$', views.BookGenericAPIView.as_view()),

    url(r'^v3/books/$', views.BookMixinGenericAPIView.as_view()),
    url(r'^v3/books/(?P<pk>.*)/$', views.BookMixinGenericAPIView.as_view()),

    url(r'^v4/books/$', views.BookListCreateAPIView.as_view()),
    url(r'^v4/books/(?P<pk>.*)/$', views.BookListCreateAPIView.as_view()),

    url(r'^v5/books/$', views.BookGenericViewSet.as_view({'get': 'my_get_list'})),
    url(r'^v5/books/(?P<pk>.*)/$', views.BookGenericViewSet.as_view({'get': 'my_get_obj'})),
]           

複制

Python進階41-drf架構(三)

Python進階41-drf架構(三)

完善單查和群查
from rest_framework.views import APIView
from utils.response import APIResponse
from . import models, serializers
from rest_framework.generics import GenericAPIView
from rest_framework.viewsets import GenericViewSet
from rest_framework import mixins


class BookGenericViewSet(mixins.RetrieveModelMixin, mixins.ListModelMixin, GenericViewSet):
    queryset = models.Book.objects.filter(is_delete=False)
    serializer_class = serializers.BookModelSerializer

    ## 真·群查
    def my_get_list(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    ## 真·單查
    def my_get_obj(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)           

複制

ModelViewSet擁有六大接口

路由
from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^v1/books/$', views.BookAPIView.as_view()),
    url(r'^v1/books/(?P<pk>.*)/$', views.BookAPIView.as_view()),

    url(r'^v2/books/$', views.BookGenericAPIView.as_view()),
    url(r'^v2/books/(?P<pk>.*)/$', views.BookGenericAPIView.as_view()),

    url(r'^v3/books/$', views.BookMixinGenericAPIView.as_view()),
    url(r'^v3/books/(?P<pk>.*)/$', views.BookMixinGenericAPIView.as_view()),

    url(r'^v4/books/$', views.BookListCreateAPIView.as_view()),
    url(r'^v4/books/(?P<pk>.*)/$', views.BookListCreateAPIView.as_view()),

    url(r'^v5/books/$', views.BookGenericViewSet.as_view({'get': 'my_get_list'})),
    url(r'^v5/books/(?P<pk>.*)/$', views.BookGenericViewSet.as_view({'get': 'my_get_obj'})),

    url(r'^v6/books/$', views.BookModelViewSet.as_view({'get': 'list', 'post': 'create'})),
    url(r'^v6/books/(?P<pk>.*)/$',views.BookModelViewSet.as_view({'get': 'retrieve', 'put': 'update', 'patch': 'partial_update'})),
]           

複制

視圖

就下面幾句話,六大接口搞定了...但是删除,一定要重寫,否則會删除資料庫

from rest_framework.viewsets import ModelViewSet


class BookModelViewSet(ModelViewSet):
    queryset = models.Book.objects.filter(is_delete=False)
    serializer_class = serializers.BookModelSerializer           

複制

1.群查

Python進階41-drf架構(三)

2.單查

Python進階41-drf架構(三)

3.單增

Python進階41-drf架構(三)

4.單改

Python進階41-drf架構(三)

重寫删除

視圖

from rest_framework.viewsets import ModelViewSet


class BookModelViewSet(ModelViewSet):
    queryset = models.Book.objects.filter(is_delete=False)
    serializer_class = serializers.BookModelSerializer

    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        if not instance:
            return APIResponse(1, '删除失敗')
        instance.is_delete = True
        instance.save()
        return APIResponse(0, '删除成功')           

複制

路由

from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^v1/books/$', views.BookAPIView.as_view()),
    url(r'^v1/books/(?P<pk>.*)/$', views.BookAPIView.as_view()),

    url(r'^v2/books/$', views.BookGenericAPIView.as_view()),
    url(r'^v2/books/(?P<pk>.*)/$', views.BookGenericAPIView.as_view()),

    url(r'^v3/books/$', views.BookMixinGenericAPIView.as_view()),
    url(r'^v3/books/(?P<pk>.*)/$', views.BookMixinGenericAPIView.as_view()),

    url(r'^v4/books/$', views.BookListCreateAPIView.as_view()),
    url(r'^v4/books/(?P<pk>.*)/$', views.BookListCreateAPIView.as_view()),

    url(r'^v5/books/$', views.BookGenericViewSet.as_view({'get': 'my_get_list'})),
    url(r'^v5/books/(?P<pk>.*)/$', views.BookGenericViewSet.as_view({'get': 'my_get_obj'})),

    url(r'^v6/books/$', views.BookModelViewSet.as_view({'get': 'list', 'post': 'create'})),
    url(r'^v6/books/(?P<pk>.*)/$',
        views.BookModelViewSet.as_view({'get': 'retrieve', 'put': 'update', 'patch': 'partial_update','delete':'destroy'})),
]           

複制

Python進階41-drf架構(三)

總結

GenericAPIView視圖集

# GenericAPIView是繼承APIView的,使用完全相容APIView
# 重點:GenericAPIView在APIView基礎上完成了哪些事
# 1)get_queryset():從類屬性queryset中獲得model的queryset資料
# 2)get_object():從類屬性queryset中獲得model的queryset資料,再通過有名分組pk确定唯一操作對象
# 3)get_serializer():從類屬性serializer_class中獲得serializer的序列化類           

複制

mixins工具集

# 1)mixins有五個工具類檔案,一共提供了五個工具類,六個工具方法:單查、群查、單增、單删、單整體改、單局部改
# 2)繼承工具類可以簡化請求函數的實作體,但是必須繼承GenericAPIView,需要GenericAPIView類提供的幾個類屬性和方法(見上方GenericAPIView基類知識點)
# 3)工具類的工具方法傳回值都是Response類型對象,如果要格式化資料格式再傳回給前台,可以通過 response.data 拿到工具方法傳回的Response類型對象的響應資料           

複制

工具視圖

# 1)工具視圖都是GenericAPIView的子類,且不同的子類繼承了不聽的工具類,重寫了請求方法
# 2)工具視圖的功能如果直接可以滿足需求,隻需要繼承工具視圖,提供queryset與serializer_class即可           

複制

視圖集

# 1)視圖集都是優先繼承ViewSetMixin類,再繼承一個視圖類(GenericAPIView或APIView)
#       GenericViewSet、ViewSet
# 2)ViewSetMixin提供了重寫的as_view()方法,繼承視圖集的視圖類,配置路由時調用as_view()必須傳入 請求名-函數名 映射關系字典
#       eg: url(r'^v5/books/$', views.BookGenericViewSet.as_view({'get': 'my_get_list'})),
#       表示get請求會交給my_get_list視圖函數處理           

複制

GenericAPIView 與 APIView 作為兩大繼承視圖的差別

# 1)GenericViewSet和ViewSet都繼承了ViewSetMixin,as_view都可以配置 請求-函數 映射
# 2)GenericViewSet繼承的是GenericAPIView視圖類,用來完成标準的 model 類操作接口
# 3)ViewSet繼承的是APIView視圖類,用來完成不需要 model 類參與,或是非标準的 model 類操作接口
#       post請求在标準的 model 類操作下就是新增接口,登陸的post不滿足
#       post請求驗證碼的接口,不需要 model 類的參與
# 案例:登陸的post請求,并不是完成資料的新增,隻是用post送出資料,得到的結果也不是登陸的使用者資訊,而是登陸的認證資訊           

複制

路由元件(了解)

from django.conf.urls import include
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
# 所有路由與ViewSet視圖類的都可以注冊,會産生 '^v6/books/$' 和 '^v6/books/(?P<pk>[^/.]+)/$'
router.register('v6/books', views.BookModelViewSet)

urlpatterns = [
    # 第一種添加子清單方式
    url(r'^', include(router.urls)),
]
# 第二種添加子清單方式
# urlpatterns.extend(router.urls)           

複制