DRF框架学习(四)
1.视图集对象的action属性
作用:
获取现在要执行的是哪一种操作。
self.action:是字符串类型,目的是获取所有执行的操作。
使用场景:
重写 get_serializer_class和get_queryset
,根据不同的操作返回不同的序列化器类和不同的查询集。
def get_serializer_class(self):
if self.action =='list':
# 返回list操作对应的序列化器类
elif self.action =='latest':
# 返回latest操作对应的序列化器类
else:
# 返回其他操作对应的序列化器类
def get_queryset(self):
if self.action =='list':
# 返回list操作所使用的查询集
elif self.action =='latest':
# 返回latest操作所使用的查询集
else:
# 返回其他操作所使用的查询集
2.路由Router(urls文件中使用)
作用:(重点)
配合视图集进行使用,动态生成视图集中处理函数的url配置项。
使用:(重点)
1.创建router类的对象
from restframe_work.routers importSimpleRouter,DefaultRouter
router =SimpleRouter()或DefaultRouter()
2.注册视图集
router.register(prefix,viewset,base_name)
例如:
# 例如:
from booktest.views importBookInfoViewSet
router.register('books',views.BookInfoViewSet,base_name='books')
3.将生成的url配置项列表添加 urlpatterns
中。
urlpatterns += router.urls
注意点:
指定Router生成视图集处理函数url配置项时,提取的参数正则表达式。
lookup_value_regex ='\d+'
2.1视图集额外处理方法url配置项的生成
- 需要给对应的方法添加action装饰器。
# detail为False 表示路径名格式应该为 books/latest/
@action(methods=['get'], detail=False)
def latest(self, request):
"""
- 需要提取参数detail改为True,不需要提取参数的时候改为False
DefaultRouter
与SimpleRouter
的区别是,DefaultRouter
会多附带一个默认的API根视图,返回一个包含所有列表视图的超链接响应数据。DefaultRouter
创建的对象,在访问url地址的时候,我们都可以在后面加一个.json
,那么后台会给我们返回json格式的数据。
3.案例
写一个视图集,提供一下两个接口
1.获取所有的图书信息 GET/books/list
2.获取指定的图书信息 GET/books/(?P\<pk>\d+)/retrieve
from rest_framework.authentication importSessionAuthentication
from rest_framework.permissions importIsAuthenticated
from rest_framework.generics importReadOnlyModelViewSet
classBookInfoViewSet(ReadOnlyModelViewSet):
# 指定当前视图所使用的查询集
queryset =BookInfo.objects.all()
# 指定当前视图所使用的序列化器类
serializer_class =BookInfoSerializer
# 指定当前视图所使用的认证类
authentication_classes =[SessionAuthentication]
# 指定当前视图所使用的权限控制类
permission_classes =[IsAuthenticated]
url文件配置:
from restframe_work.routers importDefaultRouter
router =DefaultRouter()
from booktest.views importBookInfoViewSet
router.register('books',views.BookInfoViewSet,base_name='bookss')
urlpatterns += router.urls
4.认证
DRF框架默认设置了两种全局认证方案,session认证和基本认证。
全局认证就是针对我们所有的接口。
认证需要配合权限来使用
4.1使用
DRF框架的默认全局认证方案如下,可对其进行修改,比如注释掉基本认证:
REST_FRAMEWORK ={
'DEFAULT_AUTHENTICATION_CLASSES':(
'rest_framework.authentication.SessionAuthentication', # session认证
'rest_framework.authentication.BasicAuthentication', # 基本认证
)
}
也可以在每个视图中通过设置authentication_classess属性来设置视图的认证方案:
from rest_framework.authentication importSessionAuthentication,BasicAuthentication
from rest_framework.views importAPIView
classExampleView(APIView):
# 指定当前视图的认证方式(指定后不再使用全局的认证方案)
authentication_classes =(SessionAuthentication,BasicAuthentication)
...
配合权限,如果认证失败会有两种可能的返回值:
- 401 Unauthorized 未认证
- 403 Permission Denied 权限被禁止
5.权限
权限控制可以限制用户对于视图的访问和对于具体数据对象的访问。
- 在执行视图的dispatch()方法前,会先进行视图访问权限的判断
- 在通过get_object()获取具体对象时,会进行对象访问权限的判断
DRF框架提供了四个权限控制类:
AllowAny
允许所有用户(默认的)IsAuthenticated
仅通过认证的用户IsAdminUser
仅管理员用户IsAuthenticatedOrReadOnly
认证的用户可以完全操作,否则只能get读取
5.1使用
DRF框架的默认权限控制如下:
'DEFAULT_PERMISSION_CLASSES':(
'rest_framework.permissions.AllowAny',# 允许所有人
)
可以在配置文件中设置权限管理类,如:
REST_FRAMEWORK ={
# 权限设置
'DEFAULT_PERMISSION_CLASSES':(
'rest_framework.permissions.IsAuthenticated',# 仅仅允许认证用户进行访问
)
}
也可以在具体的视图中通过 permission_classes
属性来指定某个视图所使用的权限控制类,如:
from rest_framework.permissions importIsAuthenticated
from rest_framework.views importAPIView
classExampleView(APIView):
#指定当前视图的权限控制类,指定以后不再使用全局设置
permission_classes =[IsAuthenticated]
# 还可以写成下面这个样子,但是注意逗号
permission_classes =(IsAuthenticated,)
...
5.2自定义权限(了解即可)
如需自定义权限,需继承 rest_framework.permissions.BasePermission
父类,并实现以下两个任何一个方法或全部
.has_permission(self,request,view)
是否可以访问视图, view表示当前视图对象
.has_object_permission(self,request,view,obj)
是否可以访问数据对象, view表示当前视图, obj为数据对象
例如:
classMyPermission(BasePermission):
def has_permission(self, request, view):
"""判断对使用此权限类的视图是否有访问权限"""
# 任何用户对使用此权限类的视图都有访问权限
# True有权限,False没有权限
returnTrue
def has_object_permission(self, request, view, obj):
"""判断对使用此权限类视图某个数据对象是否有访问权限"""
# 需求: 对id为1,3的数据对象有访问权限,其他的对象没有访问权限
if obj.id in(1,3):
returnTrue
returnFalse
classBookInfoViewSet(ReadOnlyModelViewSet):
# 指定当前视图所使用的查询集
queryset =BookInfo.objects.all()
# 指定当前视图所使用的序列化器类
serializer_class =BookInfoSerializer
# 指定当前视图所使用的认证类
authentication_classes =[SessionAuthentication]
# 使用自定义的权限控制类
permission_classes =[MyPermission]
6.限流
作用:可以对接口访问的频次进行限制,以减轻服务器压力。
6.1 使用
DRF框架默认没有进行全局限流设置,但是提供了配置项,我们可以在配置文件中,使用 DEFAULT_THROTTLE_CLASSES
和 DEFAULT_THROTTLE_RATES
进行全局配置。
6.1.1 可选限流类
6.1.1.1 AnonRateThrottle
限制所有匿名未认证用户,使用IP区分用户。
使用 DEFAULT_THROTTLE_RATES['anon']
来设置频次
6.1.1.2 UserRateThrottle
限制认证用户,使用User id 来区分。
使用 DEFAULT_THROTTLE_RATES['user']
来设置频次
6.1.1.3 ScopedRateThrottle
限制用户对于每个视图的访问频次,使用ip或user id。
6.1.2 限流设置
6.1.2.1针对匿名用户和认证用户分别进行限流控制
REST_FRAMEWORK ={
'DEFAULT_THROTTLE_CLASSES':(
# 针对未登录(匿名)用户的限流控制类
'rest_framework.throttling.AnonRateThrottle',
# 针对登录(认证)用户的限流控制类
'rest_framework.throttling.UserRateThrottle'
),
# 指定限流频次
'DEFAULT_THROTTLE_RATES':{
# 认证用户的限流频次
'user':'5/minutes',
# 匿名用户的限流频次
'anon':'3/minutes',
},
}
DEFAULT_THROTTLE_RATES
可以使用 second
, minute
, hour
或 day
来指明周期。
也可以在具体视图中通过throttle_classess属性来配置,如
from rest_framework.throttling importUserRateThrottle
from rest_framework.views importAPIView
classExampleView(APIView):
throttle_classes =[UserRateThrottle]
...
6.1.2.2针对匿名用户和认证用户进行统一的限流控制
REST_FRAMEWORK ={
# 针对匿名用户和认证用户进行统一的限流控制
'DEFAULT_THROTTLE_CLASSES':(
'rest_framework.throttling.ScopedRateThrottle',
),
# 设置限流频次选择项
'DEFAULT_THROTTLE_RATES':{
'upload':'3/minute',
'contacts':'5/minute'
},
}
进行了上面的配置之后,其实我们的视图还没有限流的效果,如果想实现限流,还需进行下列操作:
classContactListView(APIView):
# 指定限流频次选择项
throttle_scope ='contacts'
...
pass
classUploadView(APIView):
throttle_scope ='uploads'
...
pass
7.过滤
对于列表数据可能需要根据字段进行过滤,我们可以通过添加django-fitlter扩展来增强支持。
pip install django-filter
在配置文件中增加过滤后端的设置:
INSTALLED_APPS =[
...
'django_filters', # 需要注册应用,
]
# 过滤
REST_FRAMEWORK ={
'DEFAULT_FILTER_BACKENDS':('django_filters.rest_framework.DjangoFilterBackend',)
}
在视图中添加filter_fields属性,指定可以过滤的字段
需求:写一个类视图,提供1个接口
1.获取所有的图书信息 GET/books/
classBookListView(ListAPIView):
queryset =BookInfo.objects.all()
serializer_class =BookInfoSerializer
# 指定过滤字段,根据书名和阅读量过滤,还可以添加其他的过滤字段
filter_fields =('btitle','bread')
# 127.0.0.1:8000/books/?btitle=西游记
8.排序
对于列表数据,REST framework提供了OrderingFilter过滤器来帮助我们快速指明数据按照指定字段进行排序。
8.1使用方法:
在类视图中设置filter_backends,使用 rest_framework.filters.OrderingFilter
过滤器,REST framework会在请求的查询字符串参数中检查是否包含了ordering参数,如果包含了ordering参数,则按照ordering参数指明的排序字段对数据集进行排序。
前端可以传递的ordering参数的可选字段值需要在ordering_fields中指明。
示例:
默认是升序,如果想要实现降序的效果,那么在传入查询字符串的时候在字段名前加-,如下:
classBookListView(ListAPIView):
queryset =BookInfo.objects.all()
serializer_class =BookInfoSerializer
filter_backends =[OrderingFilter]
# 根据指定字段进行排序
ordering_fields =('id','bread','bpub_date')
# 127.0.0.1:8000/books/?ordering=-bread
9.分页(重点)
REST framework提供了分页的支持。
我们可以在配置文件中设置全局的分页方式,如:
REST_FRAMEWORK ={
'DEFAULT_PAGINATION_CLASS': '<全局分页类>',
'PAGE_SIZE':<页容量>
}
如:
REST_FRAMEWORK ={
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE':5 # 每页数目
}
9.1可选分页类
9.1.1PageNumberPagination
?page=<页码>
前端访问网址形式:
GET http://api.example.org/books/?page=4
可以在子类中定义的属性:
- page_size 每页数目
- pagequeryparam 前端发送的页数关键字名,默认为"page"
- pagesizequery_param 前端发送的每页数目关键字名,默认为None
- maxpagesize 前端最多能设置的每页数量
9.1.2LimitOffsetPagination
?offset=<偏移量>&limit=<数据条数>
前端访问网址形式:
GET http://api.example.org/books/?limit=100&offset=400
可以在子类中定义的属性:
- default_limit 默认限制,默认值与
PAGE_SIZE
设置一直 - limitqueryparam limit参数名,默认'limit'
- offsetqueryparam offset参数名,默认'offset'
- max_limit 最大limit限制,默认None
注意:如果在视图内关闭分页功能,只需在视图内设置
pagination_class =None
9.2自定义分页类
也可通过自定义Pagination类,来为视图添加不同分页行为。在视图中通过 pagination_clas
属性来指明。
classStandardResultPagination(PageNumberPagination):
# 分页默认页容量
page_size =3
# 获取分页数据时,传递也容量的参数名称
page_size_query_param ='page_size'
# 分页时最大页容量,但是不能超过最大的页容量
max_page_size =5
classBookListView(ListAPIView):
queryset =BookInfo.objects.all()
serializer_class =BookInfoSerializer
# 指定当前视图所使用的分页类
pagination_class =StandardResultPagination
通过 http://api.example.org/books/?page=<页码>&page_size=<页容量>
进行访问。
注意:视图关闭分页
pagination_class =None
10.异常处理(重点)
REST framework提供了异常处理,可以出来以下异常:
- APIException 所有异常的父类
- ParseError 解析错误
- AuthenticationFailed 认证失败
- NotAuthenticated 尚未认证
- PermissionDenied 权限决绝
- NotFound 未找到
- MethodNotAllowed 请求方式不支持
- NotAcceptable 要获取的数据格式不支持
- Throttled 超过限流次数
- ValidationError 校验失败
10.1异常处理设置
DRF框架的默认异常处理设置如下:
REST_FRAMEWORK ={
'EXCEPTION_HANDLER':'rest_framework.views.exception_handler'
}
默认使用 rest_framework.views.exception_handler
模块下的 exception_handler
函数进行异常处理。
10.2自定义异常处理
10.2.1自定义DRF框架异常处理函数
1.自定义异常处理函数
2.设置EXCEPTION_HANDLER配置项
10.2.2详解
可以在DRF框架异常处理函数的基础上,补充一些其他的异常处理,比如数据库处理:
from rest_framework.views import exception_handler as drf_exception_handler
from rest_framework import status
from django.db importDatabaseError
def exception_handler(exc, context):
# 先调用DRF框架的默认异常处理函数
response = drf_exception_handler(exc, context)
if response isNone:
view = context['view']
# 补充数据库的异常处理
if isinstance(exc,DatabaseError):
print('[%s]: %s'%(view, type(exc)))
response =Response({'detail':'服务器内部错误'}, status=status.HTTP_507_INSUFFICIENT_STORAGE)
return response
在配置文件中声明自定义的异常处理:
REST_FRAMEWORK ={
'EXCEPTION_HANDLER':'booktest.utils.exceptions.exception_handler'
}