过滤排序分页
过滤排序分页
权限,认证(了解)
权限源码
# 继承了APIView,才有的---》执行流程---》dispatch中----》三大认证
#1 APIView的dispatch的大约497行self.initial(request, *args, **kwargs)
def initial(self, request, *args, **kwargs):
self.perform_authentication(request) # 登陆
self.check_permissions(request) # 权限
self.check_throttles(request) # 频率
# 2 读权限:APIView的方法self.check_permissions(request)
def check_permissions(self, request):
# permission_classes = [AdminPermission]
# self.get_permissions()我们配置再视图类上permission_classes列表中的认证类,一个个的对象
# self.get_permissions() 是 [AdminPermission(),]
for permission in self.get_permissions():
# 写的权限类,要重写has_permission方法
# 猜permission是我们写的权限类的对象
# self 是视图类的对象(BookView,PublisViwe)
if not permission.has_permission(request, self): # 权限没通过。调用的是我们自己重写的这个方法
self.permission_denied(
request,
# self.message 错误文字
message=getattr(permission, 'message', None),
code=getattr(permission, 'code', None)
)
# 3 读 APIView--->self.get_permissions
def get_permissions(self):
return [permission() for permission in self.permission_classes]
# 翻译:
l=[]
for permission in self.permission_classes:
l.append(permission())
return l
# 记住:
- 写的权限类,一定要写一个方法has_permission,返回True或False
- 配置再视图类上
补充
# 1 视图类的方法,必须返回 4件套或drf的Response
# 2 return和raise完全不一样
# 3 视图类继承了
视图类:ViewSetMixin,ListModelMixin----》查询所有好多代码不用写----》可以自动生成路由
router.register('book',BookView,'book')
/book/--->get请求过来被映射了 list---》执行视图类中的list----》
BookView中写了get方法,根本不会执行
自动生成路由
# 4 作业
0 认证类的token从请求头中取
1 登录接口,编写图书的5个接口
-不登录就能查询所有图书
-查询单条,新增,修改,删除,都需要登录后才访问
-删除和修改要超级管理员才能操作
-所有接口,一秒钟只能访问2次
认证源码
# 继承了APIView,才有的---》执行流程---》dispatch中----》三大认证
#1 APIView的dispatch的大约497行self.initial(request, *args, **kwargs)
def initial(self, request, *args, **kwargs):
self.perform_authentication(request)
self.check_permissions(request)
self.check_throttles(request)
# 2 self.perform_authentication(request)
def perform_authentication(self, request):
request.user # 这是个方法,包装成了数据属性
# 3 Request类的user 219 行
@property
def user(self):
if not hasattr(self, '_user'):
with wrap_attributeerrors():
self._authenticate()
return self._user
# 4 Request类的self._authenticate() 373 行
def _authenticate(self):
# self.authenticators 就是你写的认证类列表---》列表推导式---》[LoginAuth(),]
for authenticator in self.authenticators:
try:
user_auth_tuple = authenticator.authenticate(self)
except exceptions.APIException:
# 抛了异常被捕获了
if user_auth_tuple is not None:
# 如果返回了两个值,就会执行这句话
# self是Request的对象
self.user, self.auth = user_auth_tuple
return
self._not_authenticated()
# 5 Request类初始化
APIView---》dispathc的前面
# 总结:
1 认证类,必须写一个方法authenticate
2 如果认证通过,可以返回None,也可也返回两个值,但是第一个值,尽量是当前登录用户,第二个值一般放token
3 认证失败,抛异常AuthenticationFailed,继承了APIException,他能捕获
django中的翻译函数
# 只要做了国际化,会自动翻译成,当前国家的语言
from django.utils.translation import gettext_lazy as _
_('hello')
过滤
# restful规范中
-请求地址中带过滤条件
# 带过滤的接口只有:查询所有
# 内置过滤类
from rest_framework.filters import SearchFilter
class PublishView(GenericViewSet, ListModelMixin):
queryset = publish.objects.all()
serializer_class = PublishSerialzier
filter_backends = [SearchFilter]
search_fields = ['name','addr'] # 只要列表中的字段包含你搜索的字就可以匹配出来
# 如http://127.0.0.1:8000/api/ip/publish/?search=11
# 第三方过滤类
### 2.1 第三方过滤类
# pip3 install django-filter
from django_filters.rest_framework import DjangoFilterBackend
class PublishView(GenericViewSet, ListModelMixin):
queryset = publish.objects.all()
serializer_class = PublishSerialzier
filter_backends = [DjangoFilterBackend]
filterset_fields = ['name', 'addr']
# 注意:第三方的要在配置文件注册,这个是精准匹配
# 如:http://127.0.0.1:8000/api/ip/publish/?name=111出版社&addr=北京(匹配名字是111出版社地址在北京的出版社)
# 自定义过滤类 价格再100----200之间的图书
from .filter import *
class BookView(GenericViewSet, ListModelMixin):
queryset = book.objects.all()
serializer_class = BookSerialzier
filter_backends = [bookfilter] # 必须配合一个过滤类
from django.db.models import Q
from rest_framework.filters import BaseFilterBackend
class bookfilter(BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
pricemin = request.query_params.get('pricemin') # 获取价格下限
pricemax = request.query_params.get('pricemax') # 获取价格下限
# book.objects.filter(price__lt=100)
queryset = queryset.filter(Q(price__lt=pricemax) & Q(price__gt=pricemin))
return queryset
# 如:http://127.0.0.1:8000/api/ip/book/?pricemin=100&pricemax=200
# 过滤和排序可以一起使用
排序
# restful规范中
-请求地址中带过滤条件
# 带排序功能的接口:查询所有
from rest_framework.filters import OrderingFilter
class PublishView(GenericViewSet, ListModelMixin):
queryset = publish.objects.all()
serializer_class = PublishSerialzier
filter_backends = [OrderingFilter # 排序类
ordering_fields = ['name', 'id'] # 可以根据列表的字段进行排序,先后顺序无所谓字段前加-是倒序
# 具体使用如下:
# http://127.0.0.1:8000/api/ip/publish/?ordering=name,-id
分页
# 查询所有接口,过滤和排序了,但是实际上,这个接口,都需要有分页功能
-分页的展现形式
web:下一页点解
app,小程序:下滑下一页
-接口都一样,要支持分页
# drf提供给咱们,三种分页方式
# 基本分页
# 偏移分页
# 游标分页
from .page import MyPageNumberPagination, # 基本分页
MyLimitOffsetPagination, # 偏移分页
MyCursorPagination #游标分页
class BookView(GenericViewSet, ListModelMixin):
queryset = Book.objects.all()
serializer_class = BookSerialzier
# pagination_class = MyPageNumberPagination # 只能按一种方式分页,不要放到列表中了
# pagination_class = MyLimitOffsetPagination # 只能按一种方式分页,不要放到列表中了
pagination_class = MyCursorPagination # 只能按一种方式分页,不要放到列表中了
# page.py
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination
# 基本分页
class MyPageNumberPagination(PageNumberPagination):
page_size = 2 # 每页多少条
page_query_param = 'page' # 在地址中page=第几页
page_size_query_param = 'page_size' # 在地址中page_size是每页显示多少条
max_page_size = 5 # 每页最大多少条
# 偏移分页
class MyLimitOffsetPagination(LimitOffsetPagination):
default_limit = 2 # 每页多少条
limit_query_param = 'limit' # limit=3 这一页取3条
offset_query_param = 'offset' # 偏移量是多少 offset=3&limit=2 从第3条开始,拿2条
max_limit = 5 # 最多取5条
# 游标分页 速度快,但是不可以跳转
class MyCursorPagination(CursorPagination):
cursor_query_param = 'cursor' # 查询参数,其实用不到
page_size = 2 # 每页显示多少条
ordering = 'id' # 必须是要分页的数据表中的字段,一般按id来
实例
视图
from rest_framework.filters import OrderingFilter
from rest_framework.mixins import ListModelMixin
from rest_framework.viewsets import GenericViewSet
from .filter import *
# Create your views here.
from .serializer import *
class PublishView(GenericViewSet, ListModelMixin):
queryset = publish.objects.all()
serializer_class = PublishSerialzier
filter_backends = [publishfilter, OrderingFilter]
filterset_fields = ['name', 'addr']
ordering_fields = ['addr','id']
filter
from django.db.models import Q
from rest_framework.filters import BaseFilterBackend
class publishfilter(BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
name = request.query_params.get('name')
addr = request.query_params.get('addr')
if name and addr:
queryset = queryset.filter(Q(name__contains=name) | Q(addr__contains=addr))
return queryset
elif name and (not addr):
queryset = queryset.filter(name__contains=name)
return queryset
elif addr and (not name):
queryset = queryset.filter(addr__contains=addr)
return queryset
else:
return queryset
test
http://127.0.0.1:8000/api/ip/publish/?name=4&addr=%南&ordering=addr,-id
继承APIView完成以上操作
视图
class PublishView(APIView):
ordering_fields = ['addr', 'id']
def get(self, request):
queryset = publish.objects.all()
filtration = publishfilter() # 实例化过滤类
queryset = filtration.filter_queryset(request, queryset, self) # 调用内部的过滤方法
ordering = OrderingFilter() # 实例化排序类,注意要给一个列表
queryset = ordering.filter_queryset(request, queryset, self) # 调用排序类里的排序方法
paginator = MyPageNumberPagination() # 实例化分页类
qs = paginator.paginate_queryset(queryset, request, self) # 调用分页方法
ser = PublishSerialzier(instance=qs, many=True)
return Response(ser.data)
作业
# 1 写查询所有出版社接口
-可以按名字或城市 模糊 匹配
-如果城市一样,可以按id倒序排列
# 2 上述接口,带分页功能
# 3 研究权限和认证源码
#### 高级###
继承APIView,实现上面1,2