标签:目的 false reg except 传参 类集 auth 步骤 自己的
概要:
# 1 请求和响应
# 2 请求 Request对象,drf新包装的,Request.data,Request.query_params, 重写了__getattr__, request._request
# 3 json模块是否执行反序列化bytes格式
# 4 考你:视图类的方法中:self.request,就是当次请求的request
# 5 Response:类,实例化传一堆参,data=字典,status=状态码(有一堆常量),headers=响应头(字典),content_type=响应的编码方式
# 6 全局和局部配置,响应格式
# 7 drf默认配置文件,查找顺序--》先从类中属性找---》项目的setting找---》drf默认的配置找
# 8 视图家族
-APIView---》继承自View
-GenicAPIView---》APIView,做了一些扩展:
-queryset = None
-serializer_class = None
-get_queryset() 经常用
-get_serializer() 经常用
-get_serializer_class() 内部来用,外部会重写
-get_object() 经常用,获取一条数据(pk传过来)
-源码解析
queryset = self.filter_queryset(self.get_queryset()) #返回所有数据queryset对象
# lookup_url_kwarg就是pk,路由中有名分组分出来的pk
lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
# {pk:4} 4 浏览器地址中要查询的id号http://127.0.0.1:8000/books6/4/
filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
# 根据pk=4去queryset中get单个对象
obj = get_object_or_404(queryset, **filter_kwargs)
self.check_object_permissions(self.request, obj)
return obj
-5 个视图扩展类(继承了object),每个里面写了一个方法(ListModelMixin:list方法)
ListModelMixin,
CreateModelMixin,
UpdateModelMixin,
DestroyModelMixin,
RetrieveModelMixin
-GenericAPIView的视图子类,9个,继承了GenicAPIView+一个或者两个或者三个视图扩展类
CreateAPIView,
ListAPIView,
UpdateAPIView,
RetrieveAPIView,
DestroyAPIView,
ListCreateAPIView,
RetrieveUpdateDestroyAPIView,
RetrieveDestroyAPIView,
RetrieveUpdateAPIView
-视图集:ModelViewSet,ReadOnlyModelViewSet:继承了上面一堆(5个视图扩展和GenicAPIView)+自己写了一个ViewSetMixin(as_view方法),只要继承它的,路由得写成{‘get’:‘自己定义的方法’}
-ViewSet=ViewSetMixin, views.APIView :ViewSetMixin要放在前面
-GenericViewSet=ViewSetMixin+GenicAPIView
-ViewSetMixin(as_view方法)
-ViewSetMixin+APIView=ViewSet
-ViewSetMixin+GenicAPIView=GenericViewSet
源码:
def view(request, *args, **kwargs):
self = cls(**initkwargs)
if hasattr(self, ‘get‘) and not hasattr(self, ‘head‘):
self.head = self.get
self.request = request #将原生的request赋值各了对象,类的对象可以通过self.取到request
self.args = args
self.kwargs = kwargs
return self.dispatch(request, *args, **kwargs)#函数返回了request所以视图函数可以接收request
1.1.2 经过APIView时,rest_framework重新封装了request
导入使用: from rest_framework.request import Request
# 源码分析
1,重写了init方法对象装饰时字典将原request作为新request的属性
def __init__(self, request, parsers=None, authenticators=None,
negotiator=None, parser_context=None):
# 二次封装request,将原生request作为drf request对象的 _request 属性
self._request = request
2,重写了getattr方法,获取新request的属性时先去原request里查找
def __getattr__(self,item):
return getattr(self._request,item)
# 请求对象.data:前端以三种编码方式传入的数据,都可以取出来
# 请求对象..query_params 与Django标准的request.GET相同,只是更换了更正确的名称而已。
rest_framework重新封装了response,
导入:from rest-framework.response import Response
源码分析:
def __init__(self, data=None, status=None,
template_name=None, headers=None,
exception=False, content_type=None):
#data:你要返回的数据,字典
#status:返回的状态码,默认是200,
-from rest_framework import status在这个路径下,它把所有使用到的状态码都定义成了常量
#template_name 渲染的模板名字(自定制模板)
#headers:响应头,可以往响应头放东西,就是一个字典
#content_type:响应的编码格式,application/json和text/html;
# 浏览器响应成浏览器的格式,postman响应成json格式,通过配置实现的(默认配置)
#不管是postman还是浏览器,都返回json格式数据
drf配置文件的查找顺序:
# drf的配置信息,先从自己类中找--》项目的setting中找---》默认的找
-局部使用:对某个视图类有效
-在视图类中写如下,drf会优先使用自己类的配置,只对自己的类有效
from rest_framework.renderers import JSONRenderer
renderer_classes=[JSONRenderer,]
-全局使用:全局的视图类,所有请求,都有效
-在setting.py中加入如下
REST_FRAMEWORK = {
‘DEFAULT_RENDERER_CLASSES‘: ( # 默认响应渲染类
‘rest_framework.renderers.JSONRenderer‘, # json渲染器
‘rest_framework.renderers.BrowsableAPIRenderer‘, # 浏览API渲染器
)
}
1,手动写orm语句
book_list=Book.objects.all()
2,手动调用序列化器
book_ser=BookSerializer(book_list,many=True)
3,手动写业务逻辑处理不同的请求
def get(self,request):
def post(self,request):
4,视图的类需要写两个,分别对应url的有名分组传参和不传参情况.
url(r‘^api/books2/$‘, views.Books2.as_view()),
url(r‘^api/book2/(?P<num>\d+)/‘, views.Book2.as_view())
class BookView(APIView):
def get(self,request):
book_list=Book.objects.all()
book_ser=BookSerializer(book_list,many=True)
return Response(book_ser.data)
def post(self,request):
book_ser = BookSerializer(data=request.data)
if book_ser.is_valid():
book_ser.save()
return Response(book_ser.data)
else:
return Response({‘status‘:101,‘msg‘:‘校验失败‘})
class BookDetailView(APIView):
def get(self, request,pk):
book = Book.objects.all().filter(pk=pk).first()
book_ser = BookSerializer(book)
return Response(book_ser.data)
def put(self, request,pk):
book = Book.objects.all().filter(pk=pk).first()
book_ser = BookSerializer(instance=book,data=request.data)
if book_ser.is_valid():
book_ser.save()
return Response(book_ser.data)
else:
return Response({‘status‘: 101, ‘msg‘: ‘校验失败‘})
def delete(self,request,pk):
ret=Book.objects.filter(pk=pk).delete()
return Response({‘status‘: 100, ‘msg‘: ‘删除成功‘})
简化步骤,在类里直接申明了操作哪张表,调用哪个序列化器:
queryset = models.Booklib.objects
serializer_class = BookModelSerializer
在请求的函数种调用申明的列表和序列化器会自动传入对象
book=self.get_queryset().filter(pk=num).first()
ser_obj=self.get_serializer(book)
下面分别对应5种方法的注意事项:
class Books2(GenericAPIView):
queryset = models.Booklib.objects.all()
serializer_class = BookModelSerializer
def get(self,request):
book=self.get_queryset()
book_ser=self.get_serializer(book,many=True)
return CommomResponse(data=book_ser.data,headers={‘key‘:‘value‘})
def post(self,request):#创建,修改了id为只读属性,创建时不需要id参数
book_ser=self.get_serializer(data=request.data)
if book_ser.is_valid():
book_ser.save()
return CommomResponse(data=book_ser.data)
else:
return CommomResponse(101,‘数据不和法‘,book_ser.errors)
class Book2(GenericAPIView):
queryset = models.Booklib.objects
serializer_class = ser.BookModelSerializer
def get(self,request,num):
book=self.get_queryset().filter(pk=num).first()
ser_obj=self.get_serializer(book)
return CommomResponse(data=ser_obj.data)
def delete(self,request,num):
book=self.get_queryset().filter(pk=num).delete()
return CommomResponse(msg=‘删除成功‘)
def put(self,request,num):
book=self.get_queryset().filter(pk=num).first()#只有一个值时一定有用.first()
ser_obj=self.get_serializer(book,request.data)
if ser_obj.is_valid():
ser_obj.save() #这是序列化器的save方法,不是queryset的
return CommomResponse(data=ser_obj.data)
else:
return CommomResponse(msg=‘数据不合法‘)
5个视图扩展类:直接继承object的类,这些类能自动能更具请求方式相应
ListModelMixin:获取所有数据
RetrieveModelMixin:获取一条数据
CreateModelMixin:创建
UpdateModelMixin:更新
DestroyModelMixin:删除
使用方法:在相应的请求函数下调用对应的函数,有参数的还得传参:
class Books3(GenericAPIView,ListModelMixin,CreateModelMixin):
queryset = models.Booklib.objects
serializer_class = ser.BookModelSerializer
def get(self,request):
return self.list(request)
def post(self,request):
return self.create(request)
class Book3(GenericAPIView,RetrieveModelMixin,DestroyModelMixin,UpdateModelMixin):
queryset = models.Booklib.objects
serializer_class = ser.BookModelSerializer
def get(self,request,pk):
return self.retrieve(request,pk)
def put(self,request,pk):
return self.update(request,pk)
def delete(self,request,pk):
return self.destroy(request,pk)
分别是:
5个基础组合类
CreateAPIView,ListAPIView,RetrieveAPIView,DestroyAPIView,UpdateAPIView
4个扩展组合类
ListCreateAPIView,RetrieveUpdateAPIView,RetrieveDestroyAPIView,RetrieveUpdateDestroyAPIView
这9个类集合了API类和ModelMixin类的优点,同时又更进一步,类体写了请求对应的操作,继承这个类之后只需要申明操作票那个表和指定那个序列化器.
使用方法:只需要这6行代码实现面的功能
class Books4(ListCreateAPIView):
queryset = models.Booklib.objects
#这里需要一个queryse对像所以要去到object
serializer_class = ser.BookModelSerializer
class Book4(RetrieveUpdateDestroyAPIView):
queryset = models.Booklib.objects
serializer_class = ser.BookModelSerializer
到此为止,试图函数的代码已经大大的减少 ,但是还得自己手动配置路由路径和两个视图类的对应关系.
作用:只需要编写一个视图类来对应两个url
该类重写了的as_view功能匹配了请求的method和url视图层action,并且调用函数
注意:因为ViewSetMixin重写了as_view,查找as_view时会现去继承的第一父类查找,如果APIView在前则,不会执行重写的as_view导致功能失效.
当然这里的APIView也可以是GenericAPIView
class Book05(ViewSetMixin,APIView):
def get_one_book(self,request,pk):
obj_list = models.Booklib.objects.filter(pk=pk).first()
ser_book = ser.BookModelSerializer(obj_list)
return CommomResponse(data=ser_book.data)
def get_books(self,request):
obj_list = models.Booklib.objects.all()
ser_book=ser.BookModelSerializer(obj_list,many=True)
return CommomResponse(data=ser_book.data)
URL写法:
url(r‘^api/books5/$‘, views.Book05.as_view(actions={‘get‘:‘get_books‘})),
url(r‘^api/book5/(?P<pk>\d+)/‘, views.Book05.as_view(actions={‘get‘:‘get_one_book‘})),
ModelViewSet的父类:
GenericViewSet 5个视图拓展类(这5个类都直接继承object)
GenericViewSet继承了GenericAPIView和ViewSetMixin(该类直接继承object)
GenericAPIView的继承关系就比较清晰了:
GenericAPIView>>>APIView>>>View>>>object
请求与函数的对应:
get-->list 获取多个
get-->retrieve 获取一个
post-->create
put-->update
delete-->delete
class Book06(ModelViewSet):
queryset = models.Booklib.objects
serializer_class = BookModelSerializer
def list(self, request, *args, **kwargs):
queryset = self.get_queryset()
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data[0:2])#此处使得获取所有数据的请求改为只获取前两个数据,这是通过重写list方法实现的
@action([‘GET‘], False) #通过action装饰器自动生成list_3对应的url,False即不接受参数
def list_3(self, request):
pass
该类写在路由层,作用为自动生成与视图类关联的路由
router=routers.SimpleRouter()
router.register(‘book‘,views.Book06)
urlpatterns+=router.urls#将自动生成的路由加入到原路由列表中
到此为止,ModelViewSet类和SimpleRouter类最终将上述的问题都解决了
标签:目的 false reg except 传参 类集 auth 步骤 自己的
原文地址:https://www.cnblogs.com/Franciszw/p/13281083.html