十大接口與視圖家族

十大接口與視圖家族

一、序列化類外鍵字段的覆蓋

一、在序列化類中自定義字段,名字與model類中屬性名一致,稱之爲覆蓋(覆蓋的是屬性的全部規則:extra_kwargs中的、model字段提供的默認的、數據庫惟一約束等校驗規則)數據庫

二、外鍵覆蓋字段用PrimaryKeyRelatedField來實現,能夠作到只讀、只寫、可讀可寫三種app

  • 只讀:read_only = True工具

  • 只寫:queryset = 關聯表的queryset,write_onlypost

  • 可讀可寫:queryset = 關聯表的queryset優化

三、當外界關聯的數據有多個時,須要標識many = Trueui

class BookModelSerializer(serializers.ModelSerializer):
    # 如何覆蓋外鍵字段
    # publish = serializers.PrimaryKeyRelatedField(read_only=True)  # 只讀
    # publish = serializers.PrimaryKeyRelatedField(queryset=models.Publish.objects.all(), write_only=True)  # 只寫
    # publish = serializers.PrimaryKeyRelatedField(queryset=models.Publish.objects.all())  # 可讀可寫
​
    publish = serializers.PrimaryKeyRelatedField(queryset=models.Publish.objects.all())
    authors = serializers.PrimaryKeyRelatedField(queryset=models.Author.objects.all(), many=True)
​
    class Meta:
        model = models.Book
        fields = ('name', 'price', 'image', 'publish', 'authors')

二、十大接口序列化

    # Baseserializer類中各參數含義
    def __init__(self, instance=None, data=empty, **kwargs):
        pass
  • instance:對象類型賦值給instanceurl

  • data:請求來的數據賦值給dataspa

  • kwargs:內部有三個屬性:many、partial、contextrest

    • many:操做對象或數據時有多個時many=Truecode

    • partial:在修改需求時校驗全部的字段required=False時使用partial=True

    • context:用於視圖類和序列化類直接傳參使用

一、初始化序列化類,設置partial = True能夠將全部的反序列化字段required設置爲False(提供就校驗,不提供就不校驗),能夠在局部修改接口的時候使用

二、初始化序列化類,設置context = {...},在序列化類操做self.context,實現視圖類和序列化類數據互通

三、只有要完成資源羣改這種需求的時候,才須要自定義ListSerializer綁定給自定義的ModelSerializer,重寫update方法來實現需求

六個必備接口:單查、羣查、單增、單刪、單總體改、單局部改

四個額外接口(瞭解):羣增、羣刪、羣總體改、羣局部改

一、單查、羣查

單查接口:/books/pk/

羣查接口:/books/

class BookAPIView(APIView):
    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        # 單查,未刪除的
        if pk:
            obj = models.Book.object.filter(is_delete=False,pk=pk).first()
            serializer = serializers.BookModelSerializer(instance=obj)
            # 此處的APIResponse是自定義的二次封裝的Response
            return APIResponse(result=serializer.data)
        # 羣查
        else:
            queryset = models.Book.object.filter(is_delete=False).all()
            serializer = serializers.BookModelSerializer(instance=queryset, many=True)
            return APIResponse(results=serializer.data)

二、單增、羣增

單增接口:/books/ 數據:dict

羣增接口:/books/ 數據:list

區分是單增仍是羣增就是判斷request.data是dict仍是list

def post(self, request, *args, **kwargs):
    # 單增
    if not isinstance(request.data, list):
        serialiazer = serializer.BookModelSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)  # 校驗失敗直接拋異常
        obj = serialiazer.save()  # 存入數據庫中
        return APIResponse(result=serializer.BookModelSerializer(obj).data, http_status=201)
    else:
        # 羣增
        serialiazer = serializer.BookModelSerializer(data=request.data, many=True)
        serializer.is_valid(raise_exception=True)  # 校驗失敗直接拋異常
        objs = serialiazer.save()  # 存入數據庫中
        return APIResponse(result=serializer.BookModelSerializer(objs, many=True).data, http_status=201)

三、單刪、羣刪

單刪羣刪接口不須要利用序列化,能夠直接操做數據庫

單刪接口:/books/pk/

羣刪接口:/books/ 數據:[pk1, ...., pkn]

    def delete(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if pk:
            pks = [pk]  # 單刪假裝成羣刪一條
        else:
            pks = request.data  # 羣刪的數據就是羣刪的主鍵們
        try:
            rows = models.Book.objects.filter(is_delete=False, pk__in=pks).update(is_delete=True)
        except:
            # 若是傳的request.data提交的數據亂七八糟的,ORM操做就會異常
            return APIResponse(1, '數據有誤')
        if rows:  # 受影響行數,只要有就刪除成功
            return APIResponse(0, '刪除成功')
        # 若是傳的都是已經刪除過的,沒有受影響行數就會刪除失敗
        return APIResponse(2, '刪除失敗')

四、單總體改、羣總體改

單總體改接口:/books/pk/ 數據:dict

羣總體改接口:/books/ 數據:[{pk:1, ...}, ..., {pk:n, ...}] 或者 {pks: [pk1, ..., pkn], data: [{}, ..., {}]}通常都用第一種

    
def put(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if pk:  #
            try:
                instance = models.Book.objects.get(is_delete=False, pk=pk)
            except:
                return APIResponse(1, 'pk error', http_status=400)
            # 序列化類同時賦值instance和data,表明用data從新更新instance => 修改
            serializer = serializers.BookModelSerializer(instance=instance, data=request.data)
            serializer.is_valid(raise_exception=True)
            obj = serializer.save()
            return APIResponse(result=serializers.BookModelSerializer(obj).data)
        else:  #
            """ 分析request.data數據 [{'pk':1, 'name': '', 'publish': 1, 'authors': [1, 2]}, ...]
            1)從 request.data 中分離出 pks 列表
            2)pks中存放的pk在數據庫中沒有對應數據,或者對應的數據已經被刪除了,這些不合理的pk要被剔除
            3)pks最終轉換獲得的 objs 列表長度與 request.data 列表長度不一致,就是數據有誤
            """
            pks = []
            try:  # 只要不是要求的標準數據,必定會在下方四行代碼某一行拋出異常
                for dic in request.data:
                    pks.append(dic.pop('pk'))
                objs = models.Book.objects.filter(is_delete=False, pk__in=pks)
                assert len(objs) == len(request.data)  # 兩個列表長度必須一致
            except:
                return APIResponse(1, '數據有誤', http_status=400)
​
            serializer = serializers.BookModelSerializer(instance=objs, data=request.data, many=True)
            serializer.is_valid(raise_exception=True)
            objs = serializer.save()
            return APIResponse(result=serializers.BookModelSerializer(objs, many=True).data)

五、單局部改、羣局部改

跟單總體改和羣總體改同樣,只不過加了一個partial=True

單局部改接口:/books/pk/ 數據:dict

羣局部改接口: /books/ 數據:[{pk:1, ...}, ..., {pk:n, ...}] 或者 {pks: [pk1, ..., pkn], data: [{}, ..., {}]}通常都用第一種

def put(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if pk:  #
            try:
                instance = models.Book.objects.get(is_delete=False, pk=pk)
            except:
                return APIResponse(1, 'pk error', http_status=400)
            # 序列化類同時賦值instance和data,表明用data從新更新instance => 修改
            serializer = serializers.BookModelSerializer(instance=instance, data=request.data)
            serializer.is_valid(raise_exception=True)
            obj = serializer.save()
            return APIResponse(result=serializers.BookModelSerializer(obj).data)
        else:  #
            """ 分析request.data數據 [{'pk':1, 'name': '', 'publish': 1, 'authors': [1, 2]}, ...]
            1)從 request.data 中分離出 pks 列表
            2)pks中存放的pk在數據庫中沒有對應數據,或者對應的數據已經被刪除了,這些不合理的pk要被剔除
            3)pks最終轉換獲得的 objs 列表長度與 request.data 列表長度不一致,就是數據有誤
            """
            pks = []
            try:  # 只要不是要求的標準數據,必定會在下方四行代碼某一行拋出異常
                for dic in request.data:
                    pks.append(dic.pop('pk'))
                objs = models.Book.objects.filter(is_delete=False, pk__in=pks)
                assert len(objs) == len(request.data)  # 兩個列表長度必須一致
            except:
                return APIResponse(1, '數據有誤', http_status=400)
​
            serializer = serializers.BookModelSerializer(instance=objs, data=request.data, many=True)
            serializer.is_valid(raise_exception=True)
            objs = serializer.save()
            return APIResponse(result=serializers.BookModelSerializer(objs, many=True).data)

三、視圖家族

視圖基類:APIView、GenericAPIView

視圖工具類:mixins包下的五個類(六個方法)

工具視圖類:generics包下的全部GenericAPIView的子類

視圖集:viewsets包下的類

一、GenericAPIView基類

基本不會單獨使用,是高級視圖類的依賴基礎

  1. GenericAPIView繼承了APIView全部的APIView子類寫法再繼承GenericAPIView時能夠保存一致

  2. GenericAPIView給咱們提供了三個屬性queryset、serializer_class、lookup_field

  3. GenericAPIView給咱們提供了三個方法get_queryset、get_serializer、get_obj

二、mixins包存放了視圖工具類(不能單獨使用,必須配合GenericAPIView使用)

CreateModelMixin:單增工具類 create方法

RetrieveModelMixin:單查工具類 retrieve方法

ListModelMixin:羣查工具類 list方法

UpdateModelMixin:單總體局部改工具類 update方法

DestroyModelMixin:單刪工具類 destory方法

三、generic包下的全部GenericAPIView的子類

就是繼承GenericAPIView和不一樣的mixins下的工具類的組合

一、定義的視圖類,繼承generic包下已有的特色GenericAPIView子類,能夠在只初始化queryset和serializer_class兩個類屬性後,就獲取特色的功能

二、定義的視圖類,本身繼承GenericAPIView基類,再任意組合mixins包下的一個或多個工具類,能夠實現自定義的工具視圖類,獲取特色的功能或功能們

注意:

  1. 在這些模式下,不能實現單查和羣查共存,可是能夠加邏輯區分,也能夠用視圖集

  2. DestroyModelMixin工具類提供的destory方法默認是從數據庫中刪除數據,因此通常刪除數據的需求都是自定義邏輯

# ----------------------------- 過渡寫法:瞭解 -----------------------------
from rest_framework.generics import GenericAPIView
class BookV1APIView(GenericAPIView):
    # 將數據和序列化提高爲類屬性,全部的請求方法均可以複用
    queryset = models.Book.objects.filter(is_delete=False).all()  # ORM優化機制一次只能取出21條數據
    serializer_class = serializers.BookModelSerializer
    lookup_field = 'pk'  # 能夠省略,默認是pk,與url有名分組對應的
# 羣查
    def get(self, request, *args, **kwargs):
        # queryset = models.Book.objects.filter(is_delete=False).all()  # => 方法+屬性兩行代碼
        queryset = self.get_queryset()
        # serializer = serializers.BookModelSerializer(instance=queryset, many=True)  # => 方法+屬性兩行代碼
        serializer = self.get_serializer(instance=queryset, many=True)
        return APIResponse(results=serializer.data)
​
    # 單查
    # def get(self, request, *args, **kwargs):
    #     obj = self.get_object()
    #     serializer = self.get_serializer(obj)
    #     return APIResponse(results=serializer.data)
# 單增
    def post(self, request, *args, **kwargs):
        # serializer = serializers.BookModelSerializer(data=request.data)
        serializer = self.get_serializer(data=request.data)  # 一樣的步驟多了,好處就來了
        serializer.is_valid(raise_exception=True)
        obj = serializer.save()
        return APIResponse(result=self.get_serializer(obj).data, http_status=201)
    
# ----------------------------- 過渡寫法:瞭解 -----------------------------
from rest_framework.generics import GenericAPIView
from rest_framework import mixins
class BookV2APIView(GenericAPIView, mixins.RetrieveModelMixin, mixins.CreateModelMixin):
    queryset = models.Book.objects.filter(is_delete=False).all()
    serializer_class = serializers.BookModelSerializer
​
    # 單查
    def get(self, request, *args, **kwargs):
        # obj = self.get_object()
        # serializer = self.get_serializer(obj)
        # return APIResponse(results=serializer.data)
# return self.retrieve(request, *args, **kwargs)
​
        response = self.retrieve(request, *args, **kwargs)
        return APIResponse(result=response.data)
​
    # 單增
    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)
​
​
# ----------------------------- 開發寫法:經常使用 -----------------------------
from rest_framework.generics import RetrieveAPIView
class BookV3APIView(RetrieveAPIView):
    queryset = models.Book.objects.filter(is_delete=False).all()
    serializer_class = serializers.BookModelSerializer
​
    # 單查
    pass
相關文章
相關標籤/搜索