一、在序列化類中自定義字段,名字與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繼承了APIView全部的APIView子類寫法再繼承GenericAPIView時能夠保存一致
GenericAPIView給咱們提供了三個屬性queryset、serializer_class、lookup_field
GenericAPIView給咱們提供了三個方法get_queryset、get_serializer、get_obj
CreateModelMixin:單增工具類 create方法
RetrieveModelMixin:單查工具類 retrieve方法
ListModelMixin:羣查工具類 list方法
UpdateModelMixin:單總體局部改工具類 update方法
DestroyModelMixin:單刪工具類 destory方法
就是繼承GenericAPIView和不一樣的mixins下的工具類的組合
一、定義的視圖類,繼承generic包下已有的特色GenericAPIView子類,能夠在只初始化queryset和serializer_class兩個類屬性後,就獲取特色的功能
二、定義的視圖類,本身繼承GenericAPIView基類,再任意組合mixins包下的一個或多個工具類,能夠實現自定義的工具視圖類,獲取特色的功能或功能們
注意:
在這些模式下,不能實現單查和羣查共存,可是能夠加邏輯區分,也能夠用視圖集
# ----------------------------- 過渡寫法:瞭解 ----------------------------- 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