1. 程式人生 > >DRF的檢視

DRF的檢視

DRF的檢視

APIView

我們django中寫CBV的時候繼承的是View,rest_framework繼承的是APIView,那麼他們兩個有什麼不同呢~~~

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

我們可以看到,不管是View還是APIView最開始呼叫的都是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類中的第一個引數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更加精簡,清晰了~~~

現在我們知道了APIView和View的一些區別~~當然還有~~後面我們還會說~~

我們寫的檢視可能對多個表進行增刪改查,就導致我們的檢視特別多重複的程式碼~~

那麼我們嘗試著來進行封裝一下~~

未封裝版本

此時只是一本書的增刪蓋查查,假如說現有40個表呢?想到類的多型,封裝和繼承了沒?

from rest_framework.views import APIView
from rest_framework.response import Response
from djangoDemo.models import Book
from .serializers import BookSerializer


# 檢視所有的book
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  # 相當於request.POST
        # print(book_obj)
        ser_obj = BookSerializer(data=book_obj)  # 反序列化
        if ser_obj.is_valid():  # 如果檢驗成功
            ser_obj.save()  # 要呼叫create方法 需要去serializer中去寫
            return Response(ser_obj.validated_data)  # 返回一個 ser_obj.validated_data 檢驗通過的資料

        return Response(ser_obj.errors)  # 沒驗證成功 就返回  ser_obj.errors 錯誤資訊


# 檢視單條book資訊
class BookEditView(APIView):

    def get(self, request, id):
        book_obj = Book.objects.filter(id=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)
        #                       物件的本身傳進去, 資料傳進去,部分校驗=true
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.validated_data)  # 返回更新的內容
        return Response(ser_obj.errors)  # 返回錯誤資訊

    def delete(self, request, id):
        book_obj = Book.objects.filter(id).first()
        if not book_obj:
            return Response("您刪除的書籍不存在")
        return Response("")
APIView檢視
from rest_framework import serializers
from djangoDemo.models import Book


class PublisherSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    title = serializers.CharField(max_length=32)


class AuthorSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    name = serializers.CharField(max_length=32)


# 自己定義的校驗方法需要配合欄位使用   在欄位中加入 validators=[my_validate, ]
def my_validate(value):
    print(333)
    if "敏感詞彙" in value.lower():
        raise serializers.ValidationError("含有敏感詞彙")
    return value


# class BookSerializer(serializers.Serializer):
#     id = serializers.IntegerField(required=False)  # required=False 序列化去驗證,反序列化不校驗
#     title = serializers.CharField(max_length=32, validators=[my_validate, ])
#     pub_time = serializers.DateField()
#     category = serializers.CharField(source="get_category_display", read_only=True)  # source 後邊引數都會當成ORM去操作
#     post_category = serializers.IntegerField(write_only=True)  # write_only=True正序不用,反序用
#
#     publisher = PublisherSerializer(read_only=True)
#     # 內部通過外來鍵關係的id找到了publisher_obj
#     # 然後例項化並傳參 PublisherSerializer (publisher_obj)
#     publisher_id = serializers.IntegerField(write_only=True)  # 只有反序使用
#
#     authors = AuthorSerializer(many=True, read_only=True)  # read_only = True  正序使用 反序不使用
#     author_list = serializers.ListField(write_only=True)
#
#     def create(self, validated_data):
#         # validated_data 校驗通過通過的資料   就是book_obj
#         # 通過ORM操作給 book表增加資料
#         print(validated_data)
#         book_obj = Book.objects.create(title=validated_data["title"],
#                                        pub_time=validated_data["pub_time"],
#                                        category=validated_data["post_category"],
#                                        publisher_id=validated_data["publisher_id"])
#         book_obj.authors.add(*validated_data["author_list"])  # 新增對應的作者
#         print(book_obj)
#
#         return book_obj  # 返回物件 不返回就報錯
#
#     def update(self, instance, validated_data):
#         # instance 更新的book_obj 物件
#         # validated_data 校驗通過的資料
#         # ORM做更新操作
#         instance.title = validated_data.get("title", instance.title)  # ( 拿到傳過來的值,拿不到就用book物件自身的值)
#         instance.pub_time = validated_data.get("pub_time", instance.pub_time)  # 同理
#         instance.category = validated_data.get("post_category", instance.category)
#         instance.publisher_id = validated_data.get("publisher_id", instance.publisher_id)
#         if validated_data.get("author_list"):  # 取到作者(多對多)對應的值後
#             instance.authors.set(validated_data["author_list"])  # 設定對應作者的關係表的值
#         instance.save()  # 儲存下所有的值
#         return instance  # 返回book物件
#
#     # 暴露出來的鉤子函式 單欄位的校驗
#     def validate_title(self, value):
#         print(1111)
#         # vlaue 就是title的值,對value處理
#         if "python" not in value.lower():
#             raise serializers.ValidationError("title欄位必須有python")
#         return value
#
#     # 多欄位的鉤子函式
#     def validate(self, attrs):
#         print(2222)
#         # attrs 字典有你傳過來的所有的欄位
#         print(attrs)
#         if "python" in attrs["title"].lower() or attrs["post_category"] == 1:
#             return attrs
#         else:
#             raise serializers.ValidationError("分類或標題不符合要求")


class BookSerializer(serializers.ModelSerializer):
    # category_display = serializers.SerializerMethodField()
    publisher_info = serializers.SerializerMethodField(read_only=True)  # 正序校驗的欄位
    authors_info = serializers.SerializerMethodField(read_only=True)  # 正序驗證的欄位

    # def get_category_display(self, obj):
    #     # obj 就是序列化的每個book物件
    #     # return "ok"  # 此時所有的類別就是 ok(可以實現自定義展示)
    #     return obj.get_category_display()

    def get_authors_info(self, obj):
        authors_querset = obj.authors.all()  # 拿到多對多所有作者物件
        # 返回作者id和name
        return [{"id": author.id, "name": author.name} for author in authors_querset]

    def get_publisher_info(self, obj):
        # obj book物件
        publisher_obj = obj.publisher  # 拿到外來鍵對應的的出版社物件
        return {"id": publisher_obj.id, "title": publisher_obj.title}  # 返會自定義的id和名字

    class Meta:
        model = Book
        fields = "__all__"
        # depth 會讓所有的外來鍵關係欄位變成read_only = True
        # depth = 1  #  外來鍵的深度 ,外來鍵的所有欄位(比較冗餘)(開發不常用,一般自己構造)
        extra_kwargs = {"publisher": {"write_only": True}, "authors": {"write_only": True}}  # 反序校驗的欄位
serializers序列化檔案

第一次封裝

其實想想發現程式碼邏輯都相同,不同有兩點

  1.表名不同,2.序列化類不同

from rest_framework.views import APIView
from rest_framework.response import Response
from djangoDemo.models import Book
from .serializers import BookSerializer


# 第一次封裝 定義一個通用類
class GenericAPIView(APIView):
    queryset = None
    Serializer_class = None

    # 定義一個獲取物件方法
    def get_queryset(self):
        return self.queryset.all()  # 不加all() django會吧queryset集合放到快取中要通過加上.all()才能呼叫

    def get_serializer(self, *args, **kwargs):
        return self.Serializer_class(*args, **kwargs)  # 直接返回一個例項化物件


# 展示類
class ListModelMixin(object):
    def list(self, request):
        queryset = self.get_queryset()  # 繼承後獲取 模型物件(book物件集合。。)
        ser_obj = self.get_serializer(queryset, many=True)
        return Response(ser_obj.data)


# post提交類
class CreateModelMixin(object):
    def create(self, request):
        ser_obj = self.get_serializer(data=request.data)
        if ser_obj.is_valid():  # 如果檢驗成功
            ser_obj.save()  # 要呼叫create方法 需要去serializer中去寫
            return Response(ser_obj.validated_data)  # 返回一個 ser_obj.validated_data 檢驗通過的資料

        return Response(ser_obj.errors)  # 沒驗證成功 就返回  ser_obj.errors 錯誤資訊


# 檢索類(檢視單個物件的類)
class RetrieveModelMixin(object):
    def retrieve(self, request, id):
        book_obj = self.get_queryset().filter(id=id).first()
        ser_obj = BookSerializer(book_obj)
        return Response(ser_obj.data)


# 更新類(區域性更新)
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.validated_data)
        return Response(ser_obj.errors)


# 刪除類
class DestroyModelMixin(object):
    def destroy(self, request, id):
        book_obj = self.get_queryset().filter(id=id).first()
        if not book_obj:
            return Response("您刪除的書籍不存在")
        book_obj.delete()  # 記著刪除操作
        return Response("")


# 所有的book
class BookView(GenericAPIView, ListModelMixin, CreateModelMixin):  # 繼承通用類
    queryset = Book.objects.all()
    Serializer_class = BookSerializer

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

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


#  單條book資訊
class BookEditView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
    queryset = 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)
第一次封裝views檢視

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

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

# 上面我們寫的繼承類太長了~~我們再改改(*args, ***kwargs),為了傳參更安全一點

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)
第二次封裝

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

小插曲

想想可不可以路由把這些引數都傳過去呢,看看原始碼

點進as_view中檢視

 

有接收引數的位置,但是在自己類中只做了個賦值,然後傳參到父類中了

在父類中很友好的報錯了。。

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

我們看下ViewSetMixin

actions這個預設引數其實就是我們路由可以進行傳參了~~~

下面這個迴圈~可以看出~我們要傳的引數是一個欄位~key應該是我們的請求方式,value應該對應我們處理的方法~

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

第三次封裝

  路由urls.py   第三次封裝

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

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

注意一點~~用框架封裝的檢視~我們url上的那個關鍵字引數要用pk~~系統預設的~~

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

DRF的路由

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

  路由

我們可以看到~~通過框架我們可以把路由檢視都變的非常簡單~~

但是需要自定製的時候還是需要我們自己用APIView寫~~當不需要那麼多路由的時候~也不要用這種路由註冊~~

總之~~一切按照業務需要去用~~~ 

APIView

我們django中寫CBV的時候繼承的是View,rest_framework繼承的是APIView,那麼他們兩個有什麼不同呢~~~

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

我們可以看到,不管是View還是APIView最開始呼叫的都是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類中的第一個引數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更加精簡,清晰了~~~

現在我們知道了APIView和View的一些區別~~當然還有~~後面我們還會說~~

我們寫的檢視可能對多個表進行增刪改查,就導致我們的檢視特別多重複的程式碼~~

那麼我們嘗試著來進行封裝一下~~

未封裝版本

此時只是一本書的增刪蓋查查,假如說現有40個表呢?想到類的多型,封裝和繼承了沒?

from rest_framework.views import APIView
from rest_framework.response import Response
from djangoDemo.models import Book
from .serializers import BookSerializer


# 檢視所有的book
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  # 相當於request.POST
        # print(book_obj)
        ser_obj = BookSerializer(data=book_obj)  # 反序列化
        if ser_obj.is_valid():  # 如果檢驗成功
            ser_obj.save()  # 要呼叫create方法 需要去serializer中去寫
            return Response(ser_obj.validated_data)  # 返回一個 ser_obj.validated_data 檢驗通過的資料

        return Response(ser_obj.errors)  # 沒驗證成功 就返回  ser_obj.errors 錯誤資訊


# 檢視單條book資訊
class BookEditView(APIView):

    def get(self, request, id):
        book_obj = Book.objects.filter(id=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)
        #                       物件的本身傳進去, 資料傳進去,部分校驗=true
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.validated_data)  # 返回更新的內容
        return Response(ser_obj.errors)  # 返回錯誤資訊

    def delete(self, request, id):
        book_obj = Book.objects.filter(id).first()
        if not book_obj:
            return Response("您刪除的書籍不存在")
        return Response("")
APIView檢視
from rest_framework import serializers
from djangoDemo.models import Book


class PublisherSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    title = serializers.CharField(max_length=32)


class AuthorSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    name = serializers.CharField(max_length=32)


# 自己定義的校驗方法需要配合欄位使用   在欄位中加入 validators=[my_validate, ]
def my_validate(value):
    print(333)
    if "敏感詞彙" in value.lower():
        raise serializers.ValidationError("含有敏感詞彙")
    return value


# class BookSerializer(serializers.Serializer):
#     id = serializers.IntegerField(required=False)  # required=False 序列化去驗證,反序列化不校驗
#     title = serializers.CharField(max_length=32, validators=[my_validate, ])
#     pub_time = serializers.DateField()
#     category = serializers.CharField(source="get_category_display", read_only=True)  # source 後邊引數都會當成ORM去操作
#     post_category = serializers.IntegerField(write_only=True)  # write_only=True正序不用,反序用
#
#     publisher = PublisherSerializer(read_only=True)
#     # 內部通過外來鍵關係的id找到了publisher_obj
#     # 然後例項化並傳參 PublisherSerializer (publisher_obj)
#     publisher_id = serializers.IntegerField(write_only=True)  # 只有反序使用
#
#     authors = AuthorSerializer(many=True, read_only=True)  # read_only = True  正序使用 反序不使用
#     author_list = serializers.ListField(write_only=True)
#
#     def create(self, validated_data):
#         # validated_data 校驗通過通過的資料   就是book_obj
#         # 通過ORM操作給 book表增加資料
#         print(validated_data)
#         book_obj = Book.objects.create(title=validated_data["title"],
#                                        pub_time=validated_data["pub_time"],
#                                        category=validated_data["post_category"],
#                                        publisher_id=validated_data["publisher_id"])
#         book_obj.authors.add(*validated_data["author_list"])  # 新增對應的作者
#         print(book_obj)
#
#         return book_obj  # 返回物件 不返回就報錯
#
#     def update(self, instance, validated_data):
#         # instance 更新的book_obj 物件
#         # validated_data 校驗通過的資料
#         # ORM做更新操作
#         instance.title = validated_data.get("title", instance.title)  # ( 拿到傳過來的值,拿不到就用book物件自身的值)
#         instance.pub_time = validated_data.get("pub_time", instance.pub_time)  # 同理
#         instance.category = validated_data.get("post_category", instance.category)
#         instance.publisher_id = validated_data.get("publisher_id", instance.publisher_id)
#         if validated_data.get("author_list"):  # 取到作者(多對多)對應的值後
#             instance.authors.set(validated_data["author_list"])  # 設定對應作者的關係表的值
#         instance.save()  # 儲存下所有的值
#         return instance  # 返回book物件
#
#     # 暴露出來的鉤子函式 單欄位的校驗
#     def validate_title(self, value):
#         print(1111)
#         # vlaue 就是title的值,對value處理
#         if "python" not in value.lower():
#             raise serializers.ValidationError("title欄位必須有python")
#         return value
#
#     # 多欄位的鉤子函式
#     def validate(self, attrs):
#         print(2222)
#         # attrs 字典有你傳過來的所有的欄位
#         print(attrs)
#         if "python" in attrs["title"].lower() or attrs["post_category"] == 1:
#             return attrs
#         else:
#             raise serializers.ValidationError("分類或標題不符合要求")


class BookSerializer(serializers.ModelSerializer):
    # category_display = serializers.SerializerMethodField()
    publisher_info = serializers.SerializerMethodField(read_only=True)  # 正序校驗的欄位
    authors_info = serializers.SerializerMethodField(read_only=True)  # 正序驗證的欄位

    # def get_category_display(self, obj):
    #     # obj 就是序列化的每個book物件
    #     # return "ok"  # 此時所有的類別就是 ok(可以實現自定義展示)
    #     return obj.get_category_display()

    def get_authors_info(self, obj):
        authors_querset = obj.authors.all()  # 拿到多對多所有作者物件
        # 返回作者id和name
        return [{"id": author.id, "name": author.name} for author in authors_querset]

    def get_publisher_info(self, obj):
        # obj book物件
        publisher_obj = obj.publisher  # 拿到外來鍵對應的的出版社物件
        return {"id": publisher_obj.id, "title": publisher_obj.title}  # 返會自定義的id和名字

    class Meta:
        model = Book
        fields = "__all__"
        # depth 會讓所有的外來鍵關係欄位變成read_only = True
        # depth = 1  #  外來鍵的深度 ,外來鍵的所有欄位(比較冗餘)(開發不常用,一般自己構造)
        extra_kwargs = {"publisher": {"write_only": True}, "authors": {"write_only": True}}  # 反序校驗的欄位
serializers序列化檔案

第一次封裝

其實想想發現程式碼邏輯都相同,不同有兩點

  1.表名不同,2.序列化類不同

from rest_framework.views import APIView
from rest_framework.response import Response
from djangoDemo.models import Book
from .serializers import BookSerializer


# 第一次封裝 定義一個通用類
class GenericAPIView(APIView):
    queryset = None
    Serializer_class = None

    # 定義一個獲取物件方法
    def get_queryset(self):
        return self.queryset.all()  # 不加all() django會吧queryset集合放到快取中要通過加上.all()才能呼叫

    def get_serializer(self, *args, **kwargs):
        return self.Serializer_class(*args, **kwargs)  # 直接返回一個例項化物件


# 展示類
class ListModelMixin(object):
    def list(self, request):
        queryset = self.get_queryset()  # 繼承後獲取 模型物件(book物件集合。。)
        ser_obj = self.get_serializer(queryset, many=True)
        return Response(ser_obj.data)


# post提交類
class CreateModelMixin(object):
    def create(self, request):
        ser_obj = self.get_serializer(data=request.data)
        if ser_obj.is_valid():  # 如果檢驗成功
            ser_obj.save()  # 要呼叫create方法 需要去serializer中去寫
            return Response(ser_obj.validated_data)  # 返回一個 ser_obj.validated_data 檢驗通過的資料

        return Response(ser_obj.errors)  # 沒驗證成功 就返回  ser_obj.errors 錯誤資訊


# 檢索類(檢視單個物件的類)
class RetrieveModelMixin(object):
    def retrieve(self, request, id):
        book_obj = self.get_queryset().filter(id=id).first()
        ser_obj = BookSerializer(book_obj)
        return Response(ser_obj.data)


# 更新類(區域性更新)
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.validated_data)
        return Response(ser_obj.errors)


# 刪除類
class DestroyModelMixin(object):
    def destroy(self, request, id):
        book_obj = self.get_queryset().filter(id=id).first()
        if not book_obj:
            return Response("您刪除的書籍不存在")
        book_obj.delete()  # 記著刪除操作
        return Response("")


# 所有的book
class BookView(GenericAPIView, ListModelMixin, CreateModelMixin):  # 繼承通用類
    queryset = Book.objects.all()
    Serializer_class = BookSerializer

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

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


#  單條book資訊
class BookEditView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
    queryset = 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)
第一次封裝views檢視

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

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

# 上面我們寫的繼承類太長了~~我們再改改(*args, ***kwargs),為了傳參更安全一點

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)
第二次封裝

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

小插曲

想想可不可以路由把這些引數都傳過去呢,看看原始碼

點進as_view中檢視

 

有接收引數的位置,但是在自己類中只做了個賦值,然後傳參到父類中了

在父類中很友好的報錯了。。

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

我們看下ViewSetMixin

actions這個預設引數其實就是我們路由可以進行傳參了~~~

下面這個迴圈~可以看出~我們要傳的引數是一個欄位~key應該是我們的請求方式,value應該對應我們處理的方法~

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

第三次封裝

  路由urls.py   第三次封裝

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

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

注意一點~~用框架封裝的檢視~我們url上的那個關鍵字引數要用pk~~系統預設的~~

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

DRF的路由

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

  路由

我們可以看到~~通過框架我們可以把路由檢視都變的非常簡單~~

但是需要自定製的時候還是需要我們自己用APIView寫~~當不需要那麼多路由的時候~也不要用這種路由註冊~~

總之~~一切按照業務需要去用~~~