drf使用記錄(三) - 視圖
視圖之前還忘記了點啥
模型類序列化器
DRF
為我們提供了ModelSerializer
模型類序列化器來幫助我們快速創(chuàng)建一個Serializer
類
ModelSerializer
與常規(guī)的Serializer
基本相同,但有所封裝
- 基于模型類自動生成一系列字段
- 基于模型類自動為
Serializer
生成validators
菇夸,比如unique_together - 包含默認的
create()
和update()
的實現(xiàn)
在sers
應用中的serializers.py
創(chuàng)建一個UserModelSerializer
class UserModelSerializer(serializers.ModelSerializer):
"""用戶數(shù)據(jù)序列化器"""
# 繼承ModelSerializer可以不用聲明字段
class Meta:
model = User
fields = '__all__'
- model :參照哪個模型類
- fields :為模型類的哪些字段生成
字段的指定
-
fields
來明確字段谆刨,__all__
表名包含所有字段苛茂,也可以寫明具體哪些字段,如
class UserModelSerializer(serializers.ModelSerializer):
"""用戶數(shù)據(jù)序列化器"""
class Meta:
model = User
# fields = '__all__' # 所有字段
fields = ('name','age','sex')
-
exclude
排除掉哪些字段
class UserModelSerializer(serializers.ModelSerializer):
"""用戶數(shù)據(jù)序列化器"""
class Meta:
model = User
exclude = ('phone','addr')
- read_only_fields指明只讀字段,即僅用于序列化輸出的字段
class UserModelSerializer(serializers.ModelSerializer):
"""用戶數(shù)據(jù)序列化器"""
class Meta:
model = User
fields = '__all__'
read_only_fields = ('phone',)
-
extra_kwargs
為ModelSerializer
添加或修改原有的選項參數(shù)
class UserModelSerializer(serializers.ModelSerializer):
"""用戶數(shù)據(jù)序列化器"""
class Meta:
model = User
fields = '__all__'
extra_kwargs = {
'age':{'max_value':200,'required':True},
...
}
視圖相關
drf
除了在數(shù)據(jù)序列化部分簡寫代碼以外嗦哆,還在視圖中提供了簡寫操作。在原有的django.views.View
類基礎上,封裝了多個子類
請求Request
- REST framework 傳入視圖的request對象不再是
Django
默認的HttpRequest
對象伤哺,而是REST framework提供的擴展了HttpRequest
類的Request類的對象 - EST framework 提供了Parser解析器,在接收到請求后會自動根據(jù)
Content-Type
指明的請求數(shù)據(jù)類型(如JSON
者祖、表單等)將請求數(shù)據(jù)進行parse解析立莉,解析為類字典[QueryDict]
對象保存到Request對象中 -
Request
對象的數(shù)據(jù)是自動根據(jù)前端發(fā)送數(shù)據(jù)的格式進行解析之后的結(jié)果
常用屬性
data
request.data
返回解析之后的請求體數(shù)據(jù)。類似于Django
中標準的request.POST
和request.FILES
屬性七问,但提供如下特性
- 包含了解析之后的文件和非文件數(shù)據(jù)
- 包含了對
POST
蜓耻、PUT
、PATCH
請求方式解析后的數(shù)據(jù) - 利用了REST framework的parsers解析器械巡,不僅支持表單類型數(shù)據(jù)刹淌,也支持
JSON
數(shù)據(jù)
狀態(tài)碼
REST framewrok在rest_framework.status
模塊中提供了常用狀態(tài)碼常量。
1)信息告知 - 1xx
HTTP_100_CONTINUE
HTTP_101_SWITCHING_PROTOCOLS
2)成功 - 2xx
HTTP_200_OK
HTTP_201_CREATED
HTTP_202_ACCEPTED
HTTP_203_NON_AUTHORITATIVE_INFORMATION
HTTP_204_NO_CONTENT
HTTP_205_RESET_CONTENT
HTTP_206_PARTIAL_CONTENT
HTTP_207_MULTI_STATUS
3)重定向 - 3xx
HTTP_300_MULTIPLE_CHOICES
HTTP_301_MOVED_PERMANENTLY
HTTP_302_FOUND
HTTP_303_SEE_OTHER
HTTP_304_NOT_MODIFIED
HTTP_305_USE_PROXY
HTTP_306_RESERVED
HTTP_307_TEMPORARY_REDIRECT
4)客戶端錯誤 - 4xx
HTTP_400_BAD_REQUEST
HTTP_401_UNAUTHORIZED
HTTP_402_PAYMENT_REQUIRED
HTTP_403_FORBIDDEN
HTTP_404_NOT_FOUND
HTTP_405_METHOD_NOT_ALLOWED
HTTP_406_NOT_ACCEPTABLE
HTTP_407_PROXY_AUTHENTICATION_REQUIRED
HTTP_408_REQUEST_TIMEOUT
HTTP_409_CONFLICT
HTTP_410_GONE
HTTP_411_LENGTH_REQUIRED
HTTP_412_PRECONDITION_FAILED
HTTP_413_REQUEST_ENTITY_TOO_LARGE
HTTP_414_REQUEST_URI_TOO_LONG
HTTP_415_UNSUPPORTED_MEDIA_TYPE
HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE
HTTP_417_EXPECTATION_FAILED
HTTP_422_UNPROCESSABLE_ENTITY
HTTP_423_LOCKED
HTTP_424_FAILED_DEPENDENCY
HTTP_428_PRECONDITION_REQUIRED
HTTP_429_TOO_MANY_REQUESTS
HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE
HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS
5)服務器錯誤 - 5xx
HTTP_500_INTERNAL_SERVER_ERROR
HTTP_501_NOT_IMPLEMENTED
HTTP_502_BAD_GATEWAY
HTTP_503_SERVICE_UNAVAILABLE
HTTP_504_GATEWAY_TIMEOUT
HTTP_505_HTTP_VERSION_NOT_SUPPORTED
HTTP_507_INSUFFICIENT_STORAGE
HTTP_511_NETWORK_AUTHENTICATION_REQUIRED
視圖
Django REST framwork
提供的視圖的主要作用:
- 控制序列化器的執(zhí)行(檢驗坟比、保存、轉(zhuǎn)換數(shù)據(jù))
- 控制數(shù)據(jù)庫查詢的執(zhí)行
視圖基類
REST framework 提供了眾多的通用視圖基類與擴展類嚷往,以簡化視圖的編寫
- 新建一個應用
req
python manage.py startapp req
1.APIView
APIView
是REST framework提供的所有視圖的基類葛账,繼承自Django
的View
父類
rest_framework.views.APIView
req
應用中的views.py
View
from django.views import View
from django.http import HttpResponse, JsonResponse
class UserViews(View):
"""用戶View類"""
def get(self, request):
print(request)
"""打印效果:
<WSGIRequest: GET '/req/users/'> # 這是django原生提供的HttpRequest類
"""
return HttpResponse('ok')
tips
引入了
drf
后
-
FBV
和CBV
都可能會出現(xiàn)Django 'WSGIRequest' object has no attribute 'data'
這個報錯
解決辦法
FBV
模式需要從rest_framework.decorators
導入api_view
這個裝飾器
from rest_framework.decorators import api_view
@api_view
def your_views_func(request):
...
CBV
則不能繼承django
的中View
需要繼承
drf
中封裝的視圖,例如:APIView
from rest_framework.views import APIView
class YourViewsClass(APIView):
def get(self, request):
...
APIView
使用APIview提供用戶信息的5個API接口
GET /req/users/ 獲取全部數(shù)據(jù)
POST /req/users/ 添加數(shù)據(jù)
GET /req/users/(?P<pk>\d+) # 獲取一條數(shù)據(jù)
PUT /req/users/(?P<pk>\d+) # 更新一條數(shù)據(jù)
DELETE /req/users/(?P<pk>\d+) # 刪除一條數(shù)據(jù)
from django.views import View
from django.http import HttpResponse, JsonResponse
class UserViews(View):
"""用戶View類"""
def get(self, request):
print(request)
print(request.GET)
"""打印效果:
<WSGIRequest: GET '/req/users/'> # 這是django原生提供的HttpRequest類
"""
return HttpResponse('ok')
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.status import *
from sers.serializers import UserModelSerializer
from user.models import User
class UserApiviews1(APIView):
"""用戶APIView類,用于查詢單個皮仁、更新籍琳、刪除"""
def get(self, request, pk):
# 獲取單個數(shù)據(jù)
user = User.objects.get(pk=pk)
# 數(shù)據(jù)轉(zhuǎn)換[序列化過程]
serializer = UserModelSerializer(instance=user)
# 響應數(shù)據(jù)
return Response(serializer.data, HTTP_200_OK)
def put(self, request, pk):
"""在更新中調(diào)用序列化器完成數(shù)據(jù)的更新操作"""
user_obj = User.objects.get(pk=pk)
# 實例化序列化器
serializer = UserModelSerializer(instance=user_obj, data=request.data)
serializer.is_valid(raise_exception=True)
instance = serializer.save()
print(f'update {instance}')
return JsonResponse({'code': 200, 'msg': 'update success'})
def delete(self,request,pk):
"""在更新中調(diào)用序列化器完成數(shù)據(jù)的刪除操作"""
user = User.objects.filter(id=pk).first()
user.delete()
print(f'刪除{user}用戶成功')
return JsonResponse({'code': 200, 'msg': 'del success'})
class UserApiviews2(APIView):
"""用戶APIView類,用于新增菲宴、查詢?nèi)?""
def get(self, request):
"""新增用戶"""
print(request)
"""
控制臺:<rest_framework.request.Request object at 0x7efc8a7f7128>
"""
data_list = User.objects.all()
serializer = UserModelSerializer(instance=data_list, many=True)
return Response(serializer.data)
def post(self, request):
"""添加數(shù)據(jù)"""
# 接受post請求數(shù)據(jù)
data_dict = request.data
# 調(diào)用序列化器
serializer = UserModelSerializer(data=data_dict)
# 驗證
serializer.is_valid(raise_exception=True)
# 反序列化,保存數(shù)據(jù)
serializer.save()
# 響應數(shù)據(jù)
return Response(serializer.data, HTTP_200_OK)
-
GET /req/users/
:查詢所有數(shù)據(jù)
-
POST /req/users/
:新增數(shù)據(jù)
在這里插入圖片描述 GET /req/users/8/
: 查詢單個
-
PUT /req/users/8/
: 更新id=8
的用戶信息
-
DELETE /req/users/8/
: 刪除id=8
的用戶
2.GenericAPIView
[通用視圖類]
rest_framework.generics.GenericAPIView
繼承自APIVIew
趋急,主要增加了操作序列化器和數(shù)據(jù)庫查詢的方法喝峦,作用是為下面Mixin
擴展類的執(zhí)行提供方法支持。通常在使用時呜达,可搭配一個或多個Mixin
擴展類谣蠢。
提供的關于序列化器使用的屬性與方法
-
屬性:
-
serializer_class
指明視圖使用的序列化器
-
-
方法:
-
get_serializer_class(self)
當出現(xiàn)一個視圖類中調(diào)用多個序列化器時,那么可以通過條件判斷在
get_serializer_class
方法中通過返回不同的序列化器類名就可以讓視圖方法執(zhí)行不同的序列化器對象了。返回序列化器類查近,默認返回
serializer_class
眉踱,可以重寫,例如:def get_serializer_class(self): if 條件 : return Serializer1 return Serializer2
-
get_serializer(self, *args, \**kwargs)
返回序列化器對象霜威,主要用來提供給
Mixin
擴展類使用谈喳,如果我們在視圖中想要獲取序列化器對象,也可以直接調(diào)用此方法戈泼。注意婿禽,該方法在提供序列化器對象的時候,會向序列化器對象的context屬性補充三個數(shù)據(jù):request大猛、format扭倾、view,這三個數(shù)據(jù)對象可以在定義序列化器時使用胎署。
- request 當前視圖的請求對象
- view 當前請求的類視圖對象
- format 當前請求期望返回的數(shù)據(jù)格式
-
提供的關于數(shù)據(jù)庫查詢的屬性與方法
-
屬性:
-
queryset
指明使用的數(shù)據(jù)查詢集
-
-
方法:
-
get_queryset(self)
返回視圖使用的查詢集吆录,主要用來提供給
Mixin
擴展類使用,是列表視圖與詳情視圖獲取數(shù)據(jù)的基礎琼牧,默認返回queryset
屬性恢筝,可以重寫,例如:def get_queryset(self): user = self.request.user ... return # 你的自定義對象
-
get_object(self)
返回詳情視圖所需的模型類數(shù)據(jù)對象巨坊,主要用來提供給
Mixin
擴展類使用撬槽。在試圖中可以調(diào)用該方法獲取詳情信息的模型類對象。
若詳情訪問的模型類對象不存在趾撵,會返回404侄柔。
該方法會默認使用
APIView
提供的check_object_permissions
方法檢查當前對象是否有權(quán)限被訪問。
-
其他可以設置的屬性
-
pagination_class
指明分頁控制類 -
filter_backends
指明過濾控制后端
還是以增刪改查的形式
from rest_framework.generics import GenericAPIView
class UserGenericAPIView2(GenericAPIView):
queryset = User.objects.all() # 當前視圖類中操作的公共數(shù)據(jù)占调,先從數(shù)據(jù)庫查詢出來
serializer_class = UserModelSerializer # 設置類視圖中所有方法共有調(diào)用的視圖類
def get(self, request):
"""獲取所有數(shù)據(jù)"""
# 獲取模型數(shù)據(jù)
user_list = self.get_queryset()
# 調(diào)用序列化器
serializer = self.get_serializer(instance=user_list, many=True)
return Response(serializer.data, HTTP_200_OK)
def post(self, request):
"""添加數(shù)據(jù)"""
# 獲取客戶端提交的數(shù)據(jù)
serializer = self.get_serializer(data=request.data)
# 使用序列化器進行驗證
serializer.is_valid(raise_exception=True)
# 反序列化
serializer.save()
# 返回結(jié)果
return JsonResponse({'code': 200, 'msg': 'add success'})
class UserGenericAPIView1(GenericAPIView):
queryset = User.objects.all()
serializer_class = UserModelSerializer
def get(self, request, pk): # 這里的參數(shù)名必須叫pk暂题,否則要配置另一個名稱如果不配置,則報錯!
# 報錯信息: get() got an unexpected keyword argument 'pk'
instance = self.get_object()
serializer = self.get_serializer(instance=instance)
return Response(serializer.data)
def put(self, request, pk):
instance = self.get_object()
# 獲取客戶端提交數(shù)據(jù)
data = request.data
# 實例化序列化器期
serializer = self.get_serializer(instance=instance, data=data)
# 驗證
serializer.is_valid(raise_exception=True)
# 反序列化
serializer.save()
# 返回響應
return Response(serializer.data)
def delete(self, request, pk):
user = User.objects.filter(id=pk).first()
user.delete()
print(f'刪除{user}用戶成功')
return JsonResponse({'code': 200, 'msg': 'del success'})
測試略
視圖擴展類
- 提供了幾種后端視圖(對數(shù)據(jù)資源進行增刪改查)處理流程的實現(xiàn)究珊,如果需要編寫的視圖屬于這五種薪者,則視圖可以通過繼承相應的擴展類來復用代碼,減少自己編寫的代碼量
- 這五個擴展類需要搭配
GenericAPIView
父類剿涮,因為五個擴展類的實現(xiàn)需要調(diào)用GenericAPIView
提供的序列化器與數(shù)據(jù)庫查詢的方法
1)ListModelMixin
列表視圖擴展類言津,提供
list(request, *args, **kwargs)
方法快速實現(xiàn)列表視圖攻人,返回200狀態(tài)碼。該
Mixin
的list方法會對數(shù)據(jù)進行過濾和分頁悬槽。
源代碼:
class ListModelMixin(object):
"""
List a queryset.
"""
def list(self, request, *args, **kwargs):
# 過濾
queryset = self.filter_queryset(self.get_queryset())
# 分頁
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
# 序列化
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
舉例:
from rest_framework.mixins import ListModelMixin
class BookListView(ListModelMixin, GenericAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
def get(self, request):
return self.list(request)
2)CreateModelMixin
創(chuàng)建視圖擴展類怀吻,提供
create(request, *args, **kwargs)
方法快速實現(xiàn)創(chuàng)建資源的視圖,成功返回201狀態(tài)碼初婆。如果序列化器對前端發(fā)送的數(shù)據(jù)驗證失敗蓬坡,返回400錯誤。
源代碼:
class CreateModelMixin(object):
"""
Create a model instance.
"""
def create(self, request, *args, **kwargs):
# 獲取序列化器
serializer = self.get_serializer(data=request.data)
# 驗證
serializer.is_valid(raise_exception=True)
# 保存
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def perform_create(self, serializer):
serializer.save()
def get_success_headers(self, data):
try:
return {'Location': str(data[api_settings.URL_FIELD_NAME])}
except (TypeError, KeyError):
return {}
3)RetrieveModelMixin
詳情視圖擴展類烟逊,提供
retrieve(request, *args, **kwargs)
方法渣窜,可以快速實現(xiàn)返回一個存在的數(shù)據(jù)對象。如果存在宪躯,返回200乔宿, 否則返回404。
源代碼:
class RetrieveModelMixin(object):
"""
Retrieve a model instance.
"""
def retrieve(self, request, *args, **kwargs):
# 獲取對象访雪,會檢查對象的權(quán)限
instance = self.get_object()
# 序列化
serializer = self.get_serializer(instance)
return Response(serializer.data)
舉例:
class BookDetailView(RetrieveModelMixin, GenericAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
def get(self, request, pk):
return self.retrieve(request)
4)UpdateModelMixin
更新視圖擴展類详瑞,提供
update(request, *args, **kwargs)
方法,可以快速實現(xiàn)更新一個存在的數(shù)據(jù)對象同時也提供
partial_update(request, *args, **kwargs)
方法臣缀,可以實現(xiàn)局部更新成功返回200坝橡,序列化器校驗數(shù)據(jù)失敗時,返回400錯誤
源代碼:
class UpdateModelMixin(object):
"""
Update a model instance.
"""
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
if getattr(instance, '_prefetched_objects_cache', None):
# If 'prefetch_related' has been applied to a queryset, we need to
# forcibly invalidate the prefetch cache on the instance.
instance._prefetched_objects_cache = {}
return Response(serializer.data)
def perform_update(self, serializer):
serializer.save()
def partial_update(self, request, *args, **kwargs):
kwargs['partial'] = True
return self.update(request, *args, **kwargs)
5)DestroyModelMixin
刪除視圖擴展類精置,提供
destroy(request, *args, **kwargs)
方法计寇,可以快速實現(xiàn)刪除一個存在的數(shù)據(jù)對象。成功返回204脂倦,不存在返回404番宁。
源代碼:
class DestroyModelMixin(object):
"""
Destroy a model instance.
"""
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
self.perform_destroy(instance)
return Response(status=status.HTTP_204_NO_CONTENT)
def perform_destroy(self, instance):
instance.delete()
視圖代碼:
"""GenericAPIView結(jié)合視圖擴展類實現(xiàn)api接口"""
from rest_framework.mixins import ListModelMixin, CreateModelMixin
# 聲明分頁的配置類
from rest_framework.pagination import PageNumberPagination
class UserPageNumberPagination(PageNumberPagination):
# 默認每一頁顯示的數(shù)據(jù)量
page_size = 2
# 允許客戶端通過get參數(shù)來控制每一頁的數(shù)據(jù)量
page_size_query_param = "size"
max_page_size = 10
# 自定義頁碼的參數(shù)名
page_query_param = "page"
class UserMiXinGenericAPIView2(GenericAPIView, ListModelMixin, CreateModelMixin):
# 本次視圖類中要操作的數(shù)據(jù) [必填]
queryset = User.objects.all()
# 本次視圖類中要調(diào)用的默認序列化器 [必填]
serializer_class = UserModelSerializer
# 分頁器
pagination_class = UserPageNumberPagination
def get(self, request):
"""獲取多個用戶信息"""
return self.list(request)
def post(self, request):
"""添加用戶信息"""
return self.create(request)
from rest_framework.mixins import RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin
class UserMiXinGenericAPIView1(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
queryset = User.objects.all()
serializer_class = UserModelSerializer
# 在使用GenericAPIView視圖獲取或操作單個數(shù)據(jù)時,視圖方法中的代表主鍵的參數(shù)最好是pk
def get(self, request, pk):
"""獲取一條數(shù)據(jù)"""
return self.retrieve(request, pk)
def put(self, request, pk):
"""更新一條數(shù)據(jù)"""
return self.update(request, pk)
def delete(self, request, pk):
"""刪除一條數(shù)據(jù)"""
return self.destroy(request, pk)
- 測試
分頁
越來越easy
-
drf
內(nèi)置了一些同時繼承了GenericAPIView
和Mixins
擴展類的視圖子類,我們可以直接繼承這些子類九可以生成對應的API
接口 - 下面8行代碼實現(xiàn)數(shù)據(jù)的
CRUD
ListAPIView
獲取所有數(shù)據(jù)
CreateAPIView
添加數(shù)據(jù)
from rest_framework.generics import ListAPIView, CreateAPIView
class LCUserGenericAPIView(ListAPIView, CreateAPIView):
queryset = User.objects.all()
serializer_class = UserModelSerializer
RetrieveAPIView
獲取一條數(shù)據(jù)
UpdateAPIView
更新一條數(shù)據(jù)
DestorAPIView
刪除一條數(shù)據(jù)
-
RetrieveUpdateDestoryAPIView
上面三個的縮寫
from rest_framework.generics import RetrieveUpdateDestroyAPIView
class UserRetrieveUpdateDestroyAPIView(RetrieveUpdateDestroyAPIView):
queryset = User.objects.all()
serializer_class = UserModelSerializer
是不是發(fā)現(xiàn)了什么
當然
- 8行代碼赖阻,一半重復
- 查詢所有數(shù)據(jù)蝶押、添加數(shù)據(jù)是不需要聲明
pk
逐漸的,而其他的接口需要[路由沖突了] - 查詢所有數(shù)據(jù)和查詢一條數(shù)據(jù)火欧,都是屬于
get
請求[請求方法沖突了]
from rest_framework.mixins import CreateModelMixin, ListModelMixin, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin
from rest_framework.viewsets import GenericViewSet
class UserModelViewSet1(GenericViewSet, CreateModelMixin, ListModelMixin, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
queryset = User.objects.all()
serializer_class = UserModelSerializer
或者這樣棋电,和記錄(一)中的一樣
# 4行代碼
from rest_framework.viewsets import ModelViewSet
class UserModelViewSet1(ModelViewSet):
queryset = User.objects.all()
serializer_class = UserModelSerializer
路由除了記錄一那種方式,還可以這樣
urlpatterns = [
...
path("users/", views.UserModelViewSet1.as_view({"get": "list", "post": "create"})),
re_path("users/(?P<pk>\d+)/",
views.UserModelViewSet1.as_view({"get": "retrieve", "put": "update", "delete": "destroy"}))
]
測試
略