目录
回顾
1.两个视图基类
APIView
GenericAPIView:跟数据库打交道,而且需要系列化反序列,可以使用它
2.5个视图扩展类+GenericAPIView ---> 视图类
list retreieve destroy create update
正常需要写两个视图类,实现5个接口:
BookView:list create
BookDetailView:retrieve destroy update
5个接口只想写新增和更新--->>两个视图类
如果配合自动生成路由:
ViewSetMixin+list+update+GenericAPIView 可以写到一个视图类中
5个接口:自动生成路由+5个视图扩展类+GenericAPIView--->>一个视图即可
3.9个视图子集 ---> 视图类
5个 + 两两组合的 + 三个组合的
4.视图集
MOdelViewSet
ReadOnlyModelViewSet
ViewSetMixin:不是视图类,配合视图类一起用,重写了as_view ---> 路由写法变了 ---> 本质就是通过传的action做映射{'get': 'xxx'}
传action方式
自动生成方法
继承APIView+自动生成路由 ---> ViewSet
继承GenericAPIView+自动生成路由 ---> GenericViewSet
引申出来:后期在视图类中的方法,可以任意命名,只要做好映射,或自动生成即可
5.路由组件
三种写法:
传统写法:不继承ViewSetMixin及其子类的
映射写法:传actions
自动生成写法:两个类,加入到路由中:两种(includ,列表直接加)
action装饰器:
自动生成路由时,做自动生,装饰在视图类的方法上
@action(methods=['POST','GET'],detail=False)
7.登入接口 ---> 自动生成路由
ViewSetMixin+APIView login ---> 使用action装饰器装饰时 ---> post请求
取出前端传入的数据(三种格式都可以) ---> request.data
写逻辑判断是否登入成功 ---> UserToken存储登录状态
如果存在修改,不存在就更新
返回给前端
认证组件
以后,有的接口需要登录才能访问,有的接口,不登录就能访问,不登录就能访问
登录认证的限制
需求:写一个登录接口,返回token,以后只要带着token过来,就是登录了,不带就没有登录
要求:查询所有不需要登录就能访问,查询单个需要登录才能访问
认证组件的使用步骤
1.写一个认证类,继承BaseAuthentucation
2.重写authenticate方法,在该方法中实现登入认证:token在哪带的呢?如果认证它就是登录了
3.如果认证成功,返回两个值 ---> 返回None或两个值
4.认证不通过,抛异常AuthenticationFeild
5.分局部使用和全局使用
局部:只在某个视图类中使用(当前视图管理的所有接口)
class BookDetailView(ViewSetMixin, RetrieveAPIView):
authentication_class = [loginAuth]
全局:全局所有接口都生效(登录接口不要)
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES':['app01.authenticate.LoginAuth']
}
局部禁用:
class BookDetailView(ViewSetMixin, RetrieveAPIView):
authentication_class = []
新建authenticate.py文件
全局方式导入:
可以在drf的settings.py中看到
代码如下:
### 视图
# 查询所有
class BookView(ViewSetMixin, ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
# 查询单个
class BookDetailView(ViewSetMixin, RetrieveAPIView):
queryet = Book.objects.all()
serizlizer_class = BookSerializer
authentication_classes = [LoginAuth] # 需要自己写一个认证类
# 认证类代码
创建authenticate.py文件
class LoginAuth(BaseAuthtication):
def authenticate(self, request):
# 在这里实现认证,如果是登陆的,继续往后走,返回两个值,如果不是抛异常
# 请求中是否携带token,判断是否登入,放在地址栏中
token = request.query_params.get('token', None)
if token: # 前端传入tokenle了,去表中查询,如果能查到,登录了,返回两个值---> 固定的:当前登录的用户、token
user_token = UserToken.objects.filter(token=token).first()
if user_token:
return user_token.user, token
else:
# 没有登录抛异常
raise Authenticationfailed('token认证失败')
else:
raise AuthenticationFailed('token没有传')
# 路由代码
router.register('books', views.BookView, 'books')
router.register('books', views.BookDetailView, 'books')
注意:
不要在配置文件中乱导入不使用的东西,否者会报错。
因为,Django的运行是先从配置文件加载的,而导入其他的,文件都没有加载到就直接导入了就会报错。
权限组件
# 即便登录成功了,有些接口,还是不能访问因为没有权限。
# 登录后,有的接口有权限访问,有的没有权限访问
# 查询单个和查询所有,都要登录才能访问 ---> 全局认证
查询单个需要超级管理员访问
查询所有所有登录用户都能访问
# 权限是一个字段,在User表中,加入user_type字段
权限的使用
1.写一个权限类,继承BasePermission
2.重写has_permission方法,在该方法在实现权限认证,在这方法中,request.user就是当前登录用户
3.如果没有权限,返回True
4.没有权限,返回False,定制返回的中文:self.message = '中文'
5.局部使用和全局使用
局部:只在某个视图类中使用(当前视图类管理的所有接口)
class BookDetailView(ViewSetMixin, RetrieveAPIView):
permission_classes = [commonPermission]
全局:全局所有接口都生效
REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES': [
'app01.permissions.CommonPermission',
],} ---> 那么对应的user登入接口和查询所有就得禁用了
局部禁用:
class BookDetailView(ViewSetMixin, RetrieveAPIView):
permission_classes = []
当登入的用户的user_type(权限)为1时就是超级管理员就能够访问单条数据
频率组件
控制某个接口访问评率(次数)
需求:查询所有接口,同一个ip一分钟只能访问5次
使用步骤
1.写一个频率类,继承SimpleRateThrottle
2.重写get_cache_key方法,返回什么,就以什么做限制 --->ip或用户id做限制
3.配置一个类属性:scope = 'book_5_m'
4.在配置文件中配置
'DEFAULT_THROTTLE_RATES': {
'book_5_m': '5/m',
},
5.局部使用和全局使用
# 局部:
只在某个视图类中使用【当前视图类管理的所有接口】
class BookDetailView(ViewSetMixin, RetrieveAPIView):
throttle_classes = [CommonThrottle]
# 全局:
全局所有接口都生效
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': ['app01.throttling.CommonThrottle'], }
# 局部禁用:
class BookDetailView(ViewSetMixin, RetrieveAPIView):
throttle_classes = []
分用户ID和IP做限制
request.META
# request.META
一个标准的Python 字典,包含所有的HTTP 首部。具体的头部信息取决于客户端和服务器。
REMOTE_ADDR —— 客户端的IP 地址
REMOTE_HOST —— 客户端的主机名
REMOTE_USER —— 服务器认证后的用户
更多:https://www.liuqingzheng.top/python/Django%E6%A1%86%E6%9E%B6/6-%E8%A7%86%E5%9B%BE%E5%B1%82/
别忘记配类属性:scope = 'book_5_m'
在settings.py源码中
得在自己的settings文件中配置,一分钟只能访问5次。有h 1小时多少次
过滤排序
# restful规范中,要求了,请求地址中带过滤条件
5个接口中,只有一个接口需要有过滤和排序,查询所有接口
# 查询 所有图书接口,查询以 ‘红’ 开头的所有图书
继承APIView写
class BookView(APIView):
def get(self,request):
search=request.query_params.get('search')
books=Book.objects.filter()
...
内置过滤类的使用,继承GenericAPIView
class BookView(ViewSetMixin, ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
# SearchFilter内置的,固定用法,模糊匹配
# 就有过滤功能了,指定按哪个字段过滤
filter_backends = [SearchFilter]
# search_fields = ['name'] # 可以按名字模糊匹配
search_fields = ['name','price'] # 可以按名字模糊匹配或价格模糊匹配
# 可以使用的搜索方式
http://127.0.0.1:8000/api/v1/books/?search=红 # name或price中只要有红就会搜出来
# 继承APIView如何写,完全自己写,麻烦,但是清晰
在地址栏中必须以search搜索的模糊查询,查找search_fields中写的字段中包含有搜索的就会查找出来,search_fields中可以写多个字段,
使用第三方django-filter实现过滤
安装:Django-filter
from django_fliter.rest_framework import djangoFilterBackend
class BookView(ViewSetMixin, ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
permission_classes = []
authentication_classes = []
throttle_classes = []
filter_backends = ['name', 'price'] # 支持完整匹配 name=西游记&price=110
# 支持的查询方式
http://127.0.0.1:8000/api/v1/books/?price=939
http://127.0.0.1:8000/api/v1/books/?price=939&name=红楼梦
注意跟内置的不一样了:
以你在filterset_filelds中写的字段搜索的完整匹配
自己定制过滤类实现过滤
# 查询图书价格大于100的所有图书
http://127.0.0.1:8000/api/v1/books/?price_gt=100
# 第一步:定义一个过滤类。继承BaseFilterBackend,重写filter——queryset方法
class CommonFilter(BaseFilterBackend):
def filter_queryset(self, request,view):
# 在里面是实现过滤,返回qs对象,就是过滤后的数据
price_gt = requset.query_params.get('price_gt',None)
if price_gt:
qs = quesryset.filter(price__get=int(price_get))
return qs
else:
return queryset
# 第二步:配置在视图类上
class BookView(ViewSetMixin, ListAPIView):
quesryset = Book.objects.all()
serilizer_class = Bookserializer
filter_backends = [CommonFilter] # 可以定制多个,从左往右,依次执行
注意这里要CharField是不支持__gt大于的查询比较
可以自己指定字段过滤,通过在定义的过滤类里反射
排序的使用
# 内置的就够了
class BookView(ViewSetMixin, ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
filter_backends = [OrderingFilter]
ordering_fields = ['price']
# 支持的查询方法:
http://127.0.0.1:8000/api/v1/books/?ordering=price
http://127.0.0.1:8000/api/v1/books/?ordering=-price
http://127.0.0.1:8000/api/v1/books/?ordering=-id,price
分页
分页,只有查询所有接口,才有分页
# derf内置分了三个分页器对应三种分页方式
# 内置的分页类不能直接使用,需要继承,定制一些参数后才能使用
源码中GenericAPIView ---> generic中
为啥不在是一个列表了呢,因为你分页不可能会出现多个分页方式了。
分页的使用,自定义一个分页列(三种)
方式一:网页端分页
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination
class CommonpageNumberPagination(PageNumberPagination):
page_size = 2 # 每页显示2条
page_query_param = 'page' # page=10 查询第10页的数据,每页显示2条
page_size_query_param = 'size' # page=10&size=5 查询第10页,每页显示5条(这里只要你不写size每页展示2条,写了定义的size就按你写的)
max_page_size = 5 # 每页显示最大10条
方式二:偏移分页
# LimitOffset
class CommonLimitOffsetPagination(LimitOffsetPagination):
default_limit = 3 # 每页显示2条
limit_query_param = 'limit' # limit=3 取3条
offset_query_param = 'offset' # offset=1 从第一个位置开始,取limit条
max_limit = 5
# offset=3&limit=2 0 1 2 3 4 5
方式三:游标分页
# app 用下面
游标分页,只能下一页,上一页
class CommonCursorPagination(CursorPagination):
cursor_query_param = 'cursor' # 查询参数
page_size = 2 # 每页多少条
ordering = 'id' # 排序字段
以上方式一种配置在视图类上
# 配置在视图类上即可
class BookView(ViewSetMixin, ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
permission_classes = []
authentication_classes = []
throttle_classes = []
# 之前的东西一样用 ,内置的分页类不能直接使用,需要继承去定制一些参数后才能使用
# pagination_class = PageNumberPagination
#基本分页方式(基本是这种,网页端):http://127.0.0.1:8000/api/v1/books/?page=2&size=3
# pagination_class = LimitOffsetPagination
# 偏移分页 http://127.0.0.1:8000/api/v1/books/?limit=4&offset=1
# 从第一条开始,取4条
pagination_class = CommonCursorPagination
# 游标分页,只能下一页,上一页,不能跳到中间,但它的效率最高,大数据量分页,使用这种较好
标签:排序,分页,ViewSetMixin,视图,---,接口,组件,权限,class
From: https://www.cnblogs.com/xiao-fu-zi/p/17100159.html