认证组件

## 认证组件逻辑
# 1.登录认证的限制:
- 访问接口,有的需要登陆后才能访问,有的接口,不登录就能访问
# 2.准备:
-User表 : 存储用户名,密码
-UserToken表:存储用户登录状态
"""
UserToken表可以没有,如果没有,把字段直接写在User表上也可以
"""
# 3.登录接口:
-写个登录接口,返回token
-之后只要带着token过来,就是登录,不带,就没有登录。
# 4.查询所有,不需要登录就能访问
# 5.查询单个,需要登录才能访问 ## 认证组件的使用步骤
# 1.写一个认证类,继承BaseAuthentication
# 2.重写authenticate方法,在该方法中实现登录认证
# 3.如果认证成功,返回两个值【返回None或两个值】
# 4.认证不通过,抛异常AuthenticationFailed
# 5.局部使用和全局使用
- 局部:只在某个视图类中使用【当前视图类管理的所有接口】
class BookDetailView(ViewSetMixin, RetrieveAPIView):
authentication_classes = [LoginAuth]
- 全局:全局所有接口都生效(登录接口不要)
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES':['app01.authenticate.LoginAuth']
}
- 局部禁用:
class BookDetailView(ViewSetMixin, RetrieveAPIView):
authentication_classes = []

"""
注意:不要在配置文件中乱导入不使用的东西,否则会报错
"""

BookSerizlizer

## serizlizers.py
from rest_framework import serializers
from .models import Book class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ['name','price','publish_detail','author_list','publish','authors']
extra_kwargs = {'name':{'max_length': 8},
'publish_detail': {'read_only':True},
'author_list': {'read_only':True},
'publish': {'write_only': True},
'authors': {'write_only': True},}

登录接口

## 表模型
class User(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=32) class UserToken(models.Model): # 跟User是一对一
token = models.CharField(max_length=32)
user = models.OneToOneField(to='User', on_delete=models.CASCADE, null=True)
# user :反向,表名小写,所有有user字段 ## 路由
from django.contrib import admin
from django.urls import path, include
from app01 import views
from rest_framework.routers import SimpleRouter router = SimpleRouter()
router.register('user',views.UserView,'user') # 路径: api/v1/user/login 向此发送post请求
router.register('books',views.BookView,'books') urlpatterns = [
path('admin/',admin.site.urls),
path('api/v1/',include(router.urls))
] ## 视图函数
from rest_framework.viewsets import ViewSet
from rest_framework.decorators import action
from .models import User,UserToken
import uuid
from rest_framework.response import Response
## 登录接口 自动生成路由,因为登录功能不用序列化,直接继承viewset
class UserView(ViewSet):
# 1.action装饰器 写在视图类的方法上,可以自动生成路由
@action(methods=['POST'],detail=False)
def login(self,request):
username = request.data.get('username')
password = request.data.get('password')
# 过滤用户名
user = User.objects.filter(username=username,password=password).first()
if user:
# 用户存在,登录成功,生成一个随机字符串,使用uuid生成
token = str(uuid.uuid4()) # 生成一个永不重复的随机字符串
# 在user_token表中存一下
# 1.从来没有登录过,插入一条记录 / 2.登陆过,修改记录
# 有就修改,没有新增 # 1.update_or_create内部: def update_or_create(self, defaults=None, **kwargs)
# 通过kwargs传入的东西查找,能找到使用defaults的更新,否则新增一个
UserToken.objects.update_or_create(user=user, defaults={'token':token})
return Response({'code':'100','msg':'登录成功','token':token})
else:
return Response({'code':'101','msg':'用户名或密码错误'})

查询单个和查询所有视图类的

## 路由
from django.contrib import admin
from django.urls import path, include
from app01 import views
from rest_framework.routers import SimpleRouter router = SimpleRouter()
router.register('books',views.BookView,'books')
router.register('books',views.BookDetailView,'books') urlpatterns = [
path('admin/',admin.site.urls),
path('api/v1/',include(router.urls))
] ## 视图函数
from .models import Book
from .serializer import BookSerializer
from rest_framework.generics import ListAPIView,RetrieveAPIView
from rest_framework.viewsets import ViewSetMixin
from rest_framework.mixins import RetrieveModelMixin # 查询单个 # 方式一:分开写,查询所有+查询单个
class BookView(ViewSetMixin,ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
class BookDetailView(ViewSetMixin,RetrieveAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer # 方式二:合并写,查询单个+所有
class BookView(ViewSetMixin,ListAPIView,RetrieveModelMixin):
queryset = Book.objects.all()
serializer_class = BookSerializer

认证类的编写与使用

## 路由urls.py
from django.contrib import admin
from django.urls import path, include
from app01 import views
from rest_framework.routers import SimpleRouter router = SimpleRouter()
router.register('books',views.BookView,'books')
router.register('books',views.BookDetailView,'books')
router.register('user',views.UserView,'user')
# 路径: api/v1/user/login 向此发送post请求 urlpatterns = [
path('admin/',admin.site.urls),
path('api/v1/',include(router.urls))
] ## 视图类views.py
from rest_framework.viewsets import ViewSet
from rest_framework.decorators import action
from .models import User,UserToken
import uuid
from rest_framework.response import Response
## 登录接口 自动生成路由,因为登录功能不用序列化,直接继承viewset
class UserView(ViewSet):
@action(methods=['POST'],detail=False)
def login(self,request):
username = request.data.get('username')
password = request.data.get('password')
# 过滤用户名
user = User.objects.filter(username=username,password=password).first()
if user:
# 用户存在,登录成功,生成一个随机字符串,使用uuid生成
token = str(uuid.uuid4()) # 生成一个永不重复的随机字符串
# 在user_token表中存一下
# 1.从来没有登录过,插入一条记录 / 2.登陆过,修改记录
# 有就修改,没有新增 # 1.update_or_create内部: def update_or_create(self, defaults=None, **kwargs)
# 通过kwargs传入的东西查找,能找到使用defaults的更新,否则新增一个
UserToken.objects.update_or_create(user=user, defaults={'token':token})
return Response({'code':'100','msg':'登录成功','token':token})
else:
return Response({'code':'101','msg':'用户名或密码错误'})
from .models import Book
from .serializer import BookSerializer
from rest_framework.generics import ListAPIView,RetrieveAPIView
from rest_framework.viewsets import ViewSetMixin
from .authenticate import LoginAuth # 查询所有+查询单个
class BookView(ViewSetMixin,ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer class BookDetailView(ViewSetMixin,RetrieveAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
# 登录需要写一个认证类,自己写
authentication_classes = [LoginAuth] ## 自己写的认证类
# 自己写的认证类,需要继承某个类
from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions import AuthenticationFailed
from .models import UserToken
# 继承之后需要重写里面的方法,BaseAuthentication内的方法(authenticate,authenticate_header)
class LoginAuth(BaseAuthentication):
def authenticate(self, request):
# 在这里实现认证,如果是登陆的,继续往后执行返回两个值,如果不是抛出异常
# 请求中是否携带token,判断是否登录 【get请求请求体不能携带数据,排除】,放在地址栏中
token = request.query_params.get('token',None)
if token: # 前端传入token,去表中查,如果能查到,登陆了返回两个值[当前登录用户,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')

权限组件

# 1.即便登录成功了,有些接口,还是不能访问,因为没有权限
# 2.登录后,有的接口有权限访问,有的没有权限访问
# 3.查询单个和查询所有,都要登录才能访问----》全局认证
- 查询单个需要超级管理员才能访问
- 查询所有,所有登录用户都能访问
# 4.权限是一个字段,在User表中,加入user_type字段,做表迁移
- user_type = models.IntegerField(choices=((1,'超级管理员'),(2,'普通用户'),(3,'匿名用户')

权限类的编写和使用

## 模型类中
user表新增:
user_type = models.IntegerField(choices=((1,'超级管理员'),(2,'普通用户'),(3,'匿名用户') ## 视图views.py
from .permissions import CommonPermission
class BookDetailView(ViewSetMixin,RetrieveAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
# 登录需要写一个认证类,自己写
authentication_classes = [LoginAuth] # 查询单个要权限类
permission_classes = [CommonPermission] ## 重写权限类permissions.py
# 写一个类,继承基类BasePermission,重写has_permission[读源码]方法,在方法中实现权限认证,如果有权限return Ture,没有权限return False
from rest_framework.permissions import BasePermission
class CommonPermission(BasePermission):
def has_permission(self, request, view):
# 实现权限控制 ---> 知道当前登录用户是request.user
if request.user.user_type==1:
return True
else:
# 没有权限,向对象中放一个属性
# 如果表模型中使用了choice,就可以通过get_字段名_display() 拿到choice对应的中文
self.message = '您是%s,您没有权限' %request.user.get_user_type_display()
return False

权限的使用步骤

# 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',
],}
-局部禁用:
class BookDetailView(ViewSetMixin, RetrieveAPIView):
permission_classes = []

频率组件

控制某个接口访问频率(次数)

# 查询所有接口,同一个ip一分钟只能访问5次

## 视图类views.py
from .throttling import CommonThrottle
# 方式一:分开写,查询所有+查询单个
class BookView(ViewSetMixin,ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer class BookDetailView(ViewSetMixin,RetrieveAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
# 登录需要写一个认证类,自己写
authentication_classes = [LoginAuth] # 查询单个要权限类
permission_classes = [CommonPermission] # 限制访问频率次数频率类
throttle_classes = [CommonThrottle] ## 频率类throttling.py
# 频率类,不继承BaseThrottle,继承SimpleRateThrottle,写的代码少
from rest_framework.throttling import SimpleRateThrottle
# 继承SimpleRateThrottle必须重写get_cache_key
class CommonThrottle(SimpleRateThrottle):
# 配合类属性
scope = 'book_5_m'
# 配置文件中配置,要在settings.py里面配置一些配置 def get_cache_key(self, request, view):
# 返回什么,就以什么做频率限制(一般以ip或者用户id作为限制)
# 客户端ip地址从哪里拿? >>>: request.META:是一个标准的python字典,包含http请求头 >>>:REMOTE_ADDR :客户端ip地址
# return request.META.get('REMOTE_ADDR') # 以IP做限制
return request.user.pk # 以用户id做限制

控制访问频率次数的步骤

# 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 = []

过滤排序

继承APIView自定义【伪代码,未补齐】

# 继承APIView后,过滤完全需要自己写,会更麻烦,但是清晰
class BookView(APIView):
def get(self,request):
search=request.query_params.get('search')
books=Book.objects.filter()

内置过滤类的使用【继承GenericAPIView】

# restful规范中,要求了,请求地址中带过滤条件
- 5个接口中,只有查询所有接口 接口需要有过滤和排序 ## views.py
"""注掉之前代码,避免影响"""
# 过滤,必须继承GenericAPIView及其子类,才可以使用这种方式[配置过滤类的方式]
# 导入过滤排序类,过滤类SearchFilter,排序类OrderingFilter
from rest_framework.filters import SearchFilter,OrderingFilter
class BookView(ViewSetMixin,ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
authentication_classes = []
permission_classes = []
throttle_classes = []
# 内置的filter_backends,是GenericAPIView的,配上过滤类就有了过滤功能
filter_backends =[SearchFilter]
# 过滤有三层:内置,第三方,自己写的
# 可以按名字模糊去匹配
search_fields = ['name']
# 可以按名字或价格模糊去匹配
search_fields=['name','price'] # 可以使用的搜索方式
http://127.0.0.1:8000/api/v1/books/?search=h
# search=h 代表name或price中只要有h就会搜出来

使用第三方django-filter实现过滤

# 1.安装 django-filter
pip install django-filter # 2.代码
from django_filters.rest_framework import DjangoFilterBackend
class BookView(ViewSetMixin, ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
permission_classes = []
authentication_classes = []
throttle_classes = []
filter_backends = [DjangoFilterBackend]
filterset_fields = ['name','price'] # 支持完整匹配 name=xx11&price=xxx # 支持的查询方式
http://127.0.0.1:8000/api/v1/books/?price=939
http://127.0.0.1:8000/api/v1/books/?price=939&name=红楼梦

自定义定制过滤类实现过滤

#第一步; 定义一个过滤类,继承BaseFilterBackend,重写filter_queryset方法
class CommonFilter(BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
# 在里面实现过滤,返回qs对象,就是过滤后的数据
price_gt = request.query_params.get('price_gt', None)
if price_gt:
qs = queryset.filter(price__gt=int(price_gt))
return qs
else:
return queryset #第二步:这里要吧模型类models.py内的Book表price字段做修改
- 将CharField变为IntegerField后迁移 # 第三步:配置在视图类views.py上
class BookView(ViewSetMixin, ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
filter_backends = [CommonFilter] # 可以定制多个,从左往右,依次执行

排序的使用

## 排序使用内置的就够了
from rest_framework.filters import OrderingFilter
# 需要配置在filter_backends上
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

分页

# 1.分页·:只有查询所有的接口,才有分页
# 2.drf内置了三个分页器,对应了三种分页方式
# 3.内置的分页类不可以直接使用,需要继承,定制一些参数后才可以使用 #4.分页使用三种方法:
## 分页类: page.py
from rest_framework.pagination import LimitOffsetPagination,PageNumberPagination,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条
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' # 排序字段 ## 视图类views.py
# 分页功能,必须是继承GenericAPIView,如果继承APIView要自己写
from .page import CommonPageNumberPagination as PageNumberPagination\
,CommonCursorPagination as CommonCursorPagination,\
CommonLimitOffsetPagination as LimitOffsetPagination
class BookView(ViewSetMixin,ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
authentication_classes = []
permission_classes = []
throttle_classes = []
# 自己定义分页类,内置的分页类不能直接使用,需要继承,定制一些参数后才能使用 # 偏移分页 http://127.0.0.1:8000/api/v1/books/?limit=4&offset=1 : 从第一条开始,取4条
pagination_class = LimitOffsetPagination # 游标分页,只能下一页,上一页,不能跳到中间,但它的效率最高,大数据量分页,使用这种较好
pagination_class = CommonCursorPagination #
pagination_class = PageNumberPagination

drf从入门到飞升仙界 07的更多相关文章

  1. Docker从入门到飞升:基础配置安装

    导读 Docker近几年非常火,因为它是容器虚拟化,更能够充分提高硬件资源的使用率.其实利用率高不算什么,它最大的优势是能给让运维人员或者开发人员快速部署和交付资源,大大提高了工作效率.几乎所有的大企 ...

  2. 爬虫入门到放弃系列07:js混淆、eval加密、字体加密三大反爬技术

    前言 如果再说IP请求次数检测.验证码这种最常见的反爬虫技术,可能大家听得耳朵都出茧子了.当然,也有的同学写了了几天的爬虫,觉得爬虫太简单.没有啥挑战性.所以特地找了三个有一定难度的网站,希望可以有兴 ...

  3. Linux性能优化从入门到实战:07 CPU篇:CPU性能优化方法

    性能优化方法论   动手优化性能之前,需要明确以下三个问题:   (1)如何评估性能优化的效果? 确定性能的量化指标.测试优化前的性能指标.测试优化后的性能指标.   量化指标的选择.至少要从应用程序 ...

  4. sublime text 入门

    sublime text3入门教程 2017年07月19日 09:15:51 阅读数:13736 作者:sam976 转载需征得作者本人同意,谢谢. 1.介绍 所谓工欲善其事必先利其器,编码过程合理熟 ...

  5. java rmi 入门实例

    java rmi 入门实例 (2009-06-16 16:07:55) 转载▼ 标签: java rmi 杂谈 分类: java-基础    java rmi即java远程接口调用,实现了2台虚拟机之 ...

  6. drf源码剖析系列(系列目录)

    drf源码剖析系列(系列目录) 01 drf源码剖析之restful规范 02 drf源码剖析之快速了解drf 03 drf源码剖析之视图 04 drf源码剖析之版本 05 drf源码剖析之认证 06 ...

  7. Python学习从入门到放弃?我不允许!!!

    嗨,大家好 这里是汐仔 很多人都说学习python学习python,打开书本,三分钟,从入门到放弃. 这怎么可以!!!大家能选择python的原因可能是看它既简单,好入门,现在俨然是语言中的一匹黑马. ...

  8. 【Java】Lucene检索引擎详解

    基于Java的全文索引/检索引擎——Lucene Lucene不是一个完整的全文索引应用,而是是一个用Java写的全文索引引擎工具包,它可以方便的嵌入到各种应用中实现针对应用的全文索引/检索功能. L ...

  9. 转载-JavaWeb学习总结

    JavaWeb学习总结(五十三)——Web应用中使用JavaMail发送邮件 孤傲苍狼 2015-01-12 23:51 阅读:13407 评论:20     JavaWeb学习总结(五十二)——使用 ...

  10. IDEA 安装配置及操作总结(新手必看)

    Jetbrains官网下载IDEA15 我们在浏览器输入网址https://www.jetbrains.com/.选择相应的系统版本,下载最新版本的IDEA15,Windows系统双击安装文件,根据界 ...

随机推荐

  1. JAVA丑数

    leetcode题目链接 有些数的素因子只有 3,5,7,请设计一个算法找出第 k 个数.注意,不是必须有这些素因子,而是必须不包含其他的素因子.例如,前几个数按顺序应该是 1,3,5,7,9,15, ...

  2. C++数组(二):二维数组

    二维数组 什么是二维数组?二维数组就是在一维数组的基础上增加一个维度. 二维数组的定义方式 数据类型 数组名[行数][列数]; int arr[2][3]; arr[0][0] = 1; arr[0] ...

  3. JavaSE——复杂对象数组练习

    定义一个长度为3的数组,数组存储1~3名学生对象作为初始数据,学生对象的学号,姓名各不相同. 学生的属性:学号,姓名,年龄. 要求1:再次添加一个学生对象,并在添加的时候进行学号的唯一性判断. 要求2 ...

  4. CF14D题解

    CF14D Two Paths题解 题目链接 传送门 题意简述 给定一棵树,找出两条不经过相同点的最长路径,使得他们的长度乘积最大. 题目分析 首先,如果在一棵树上,两条路径没有共同的点,那么这两条路 ...

  5. OpenSSL测试-SM3

    OpenSSL测试-SM3 1.使用OpenSSL的命令计算你的8位学号的摘要值(SM3),提交截图. 运行结果 2.使用OpenSSL编程对计算"你的8位学号"SM3摘要值,提交 ...

  6. transform2d转换、transition过渡、animation动画效果、@keyframes定义动画关键帧

    transform:translate( 0 , 0 ); -ms-transform:translate( 0 , 0 ); /* IE 9 */ -webkit-transform:transla ...

  7. uniapp组件监听onShow

    在uniapp开发中,组件中需要监听页面onShow的方法 index.vue onShow() { uni.$emit('onShow', 1); //用于子组件监听onShow }, 子组件 be ...

  8. 【转载】Adobe Acrobat XI Pro闪退原因及解决办法

    https://www.cnblogs.com/zohoo/p/12704689.html https://www.cnblogs.com/zohoo/p/12704689.html

  9. windwos 系统打补丁后重启不了处理方案

    如果可以进入WinRE这个修复的高级选项,选择安全模式,是否可以进入,卸载最近安装的补丁,再重启看一下. 如果无法进入安全模式的话,那么选择cmd模式,使用下方命令.这通常会回退pending的upd ...

  10. 基于Mybatis Plus的一种查询条件构建方案

    ! 重要: 遐(瞎)想的思路, 希望各位多多建议 record为jdk17写法, 使用class也不会有问题 背景 身为资深程序员, 上班最重要的事当然是增删改查(bushi). 比如今天, 组长甩给 ...