一、rest=framework之解析器
1)解析器作用。
根据提交的数据。只解析某些特定的数据。非法数据不接收,为了系统安全问题
比如解析的数据格式有
有application/json,x-www-form-urlencoded,form-data等格式
默认支持的数据类型
'rest_framework.parsers.JSONParser' 'rest_framework.parsers.FormParser' 'rest_framework.parsers.MultiPartParser'
2)解析器局部配置
定义路由:url(r'^books/', views.Book.as_view()),
视图函数配置
from rest_framework.parsers import JSONParser # 只能解析json格式 class Book(APIView): parser_classes = [JSONParser, ] # 如果加上这行只支持json格式,不加都支持 def get(self,request,*args,**kwargs): return HttpResponse('OK') def post(self,request): print(request.data) return HttpResponse('post')
实例
说明不支持该格式
2)全局配置。在settings.py的最后加入配置,一般实际工作中,都使用json格式
REST_FRAMEWORK = { 'DEFAULT_PARSER_CLASSES':[ 'rest_framework.parsers.JSONParser' #'rest_framework.parsers.FormParser' #'rest_framework.parsers.MultiPartParser' ]}
视图函数,则不需要再添加了
3)全局配置+局部配置
解析器查询顺序,先从本地函数==》settings.py配置 ===》系统函数
即某函数需要用多个解析器,则单独配置,就不走全局配置了
二、rest=framework之认证组件
1)用户登录测试
1.1)先创建用户表
# 认证的表 class User(models.Model): nid = models.AutoField(primary_key=True) name= models.CharField(max_length=32) pwd=models.CharField(max_length=32,null=True) class UserToken(models.Model): user = models.OneToOneField(to=User,to_field='nid') token=models.CharField(max_length=64)
1.2)定义路由系统
url(r'^login/', views.Login.as_view()),
1.3)创建视图函数
# 认证组件 import hashlib,time def get_token(username): md = hashlib.md5() md.update(username.encode('utf-8')) md.update(str(time.time()).encode('utf-8')) return md.hexdigest() class Login(APIView): def post(self,requeset): response = MyResponse() name = requeset.data.get('name') pwd = requeset.data.get('pwd') user = models.User.objects.filter(name=name,pwd=pwd).first() if user: response.msg='登陆成功' # 需要生成一个随机字符串 token=get_token(name) response.token=get_token(name) # 吧随机字符串保存到数据库 #ret = models.UserToken.objects.update_or_create(user_id=user.id,kwargs={'token':token}) # 都可以 ret = models.UserToken.objects.update_or_create(user=user,defaults={'token':token}) else: response.msg='用户名或密码错误' response.status=101 return JsonResponse(response.get_dic)
1.4)登录测试
2)用户登录之后才能访问数据测试
2.1)查看定义的路由
url(r'^books/', views.Book.as_view()), url(r'^login/', views.Login.as_view()),
2.2)查看自己定义的序列化组件
from rest_framework import serializers from app01 import models class BookSer(serializers.ModelSerializer): class Meta: model = models.Book exclude=['authors'] name = serializers.CharField(error_messages={'required':'该字段必填'})
2.3)创建视图函数
# 认证组件 import hashlib,time def get_token(username): md = hashlib.md5() md.update(username.encode('utf-8')) md.update(str(time.time()).encode('utf-8')) return md.hexdigest() class Login(APIView): def post(self,requeset): response = MyResponse() name = requeset.data.get('name') pwd = requeset.data.get('pwd') user = models.User.objects.filter(name=name,pwd=pwd).first() if user: response.msg='登陆成功' # 需要生成一个随机字符串 token=get_token(name) response.token=get_token(name) # 吧随机字符串保存到数据库 #ret = models.UserToken.objects.update_or_create(user_id=user.id,kwargs={'token':token}) # 都可以 ret = models.UserToken.objects.update_or_create(user=user,defaults={'token':token}) else: response.msg='用户名或密码错误' response.status=101 return JsonResponse(response.get_dic) from app01 import myserial class Book(APIView): def get(self,request): # 必须登录才能反问数据库 # token = request.GET.get('token') token = request.query_params.get('token') ret = models.UserToken.objects.filter(token=token).first() response = MyResponse() if ret: books=models.Book.objects.all() ret = myserial.BookSer(instance=books,many=True) response.msg = '查询成功' response.data=ret.data else: response.msg = '没有登录' response.status=101 return JsonResponse(response.get_dic,safe=False)
2.4)登录测试
3)抽取验证是否登录功能,测试(减少重复验证登录的代码冗余)
只修改了视图函数的方法
import hashlib,time def get_token(username): md = hashlib.md5() md.update(username.encode('utf-8')) md.update(str(time.time()).encode('utf-8')) return md.hexdigest() class Login(APIView): def post(self,requeset): response = MyResponse() name = requeset.data.get('name') pwd = requeset.data.get('pwd') user = models.User.objects.filter(name=name,pwd=pwd).first() if user: response.msg='登陆成功' token=get_token(name) response.token=get_token(name) ret = models.UserToken.objects.update_or_create(user=user,defaults={'token':token}) else: response.msg='用户名或密码错误' response.status=101 return JsonResponse(response.get_dic) from rest_framework.exceptions import AuthenticationFailed class myAuthen(): def authenticate(self,request): token=request.query_params.get('token') ret = models.UserToken.objects.filter(token=token).first() if ret: return ret.user,ret else: raise AuthenticationFailed('您没有登录') def authenticate_header(self,value): # 该函数一定要写 pass from app01 import myserial class Book(APIView): authentication_classes = [myAuthen,] def get(self,request): response = MyResponse() books=models.Book.objects.all() ret = myserial.BookSer(instance=books,many=True) response.msg = '查询成功' response.data=ret.data return JsonResponse(response.get_dic,safe=False)
3.1)调试模式,打印输出登录的用户,即携带的token
from app01 import myserial class Book(APIView): authentication_classes = [myAuthen,] def get(self,request): response = MyResponse() print(request.user.name) # 打印用户 print(request.auth.token) # 携带的token books=models.Book.objects.all() ret = myserial.BookSer(instance=books,many=True) response.msg = '查询成功' response.data=ret.data return JsonResponse(response.get_dic,safe=False)
3.2)处理 该函数 authenticate_header 内容为pass 的问题。需要继承 BaseAuthentication 才可删除该无用函数
完善认证组件代码
import hashlib,time def get_token(username): md = hashlib.md5() md.update(username.encode('utf-8')) md.update(str(time.time()).encode('utf-8')) return md.hexdigest() class Login(APIView): def post(self,requeset): response = MyResponse() name = requeset.data.get('name') pwd = requeset.data.get('pwd') user = models.User.objects.filter(name=name,pwd=pwd).first() if user: response.msg='登陆成功' token=get_token(name) response.token=get_token(name) ret = models.UserToken.objects.update_or_create(user=user,defaults={'token':token}) else: response.msg='用户名或密码错误' response.status=101 return JsonResponse(response.get_dic) from rest_framework.exceptions import AuthenticationFailed from rest_framework.authentication import BaseAuthentication class myAuthen(BaseAuthentication): def authenticate(self,request): token=request.query_params.get('token') ret = models.UserToken.objects.filter(token=token).first() if ret: return ret.user,ret else: raise AuthenticationFailed('您没有登录') from app01 import myserial class Book(APIView): authentication_classes = [myAuthen,] def get(self,request): response = MyResponse() print(request.user.name) # 打印用户 print(request.auth.token) # 携带的token books=models.Book.objects.all() ret = myserial.BookSer(instance=books,many=True) response.msg = '查询成功' response.data=ret.data return JsonResponse(response.get_dic,safe=False)
3.3)认证组件总结
作用:校验是否登录 首先定义一个类,继承BaseAuthentication,写一个方法authenticate,在方法内部实现认证过程, 认证通过,返回None或者两个对象(user,auth),在视图类的request中可以取出来。这2个对象也可以是任意2个对象 from rest_framework.authentication import BaseAuthentication class myAuthen(BaseAuthentication): def authenticate(self,request): token=request.query_params.get('token') ret = models.UserToken.objects.filter(token=token).first() if ret: # return ret.user, ret # 要写多个认证类,这个的返回None # 最后一个认证类,返回这俩值 return ret.user,ret else: raise AuthenticationFailed('您没有登录') 局部使用:在视图类中(可以写多个) authentication_classes = [myAuthen,] 全局使用:在settings.py中写入 注意:1、全局使用时,认证组件不可以放在视图函数内 2、写了全局,局部就要删掉 3、在登录函数中,也会走认证组件,而登录是不要认证的 需要在登录中添加:authentication_classes = [] class Login(APIView): authentication_classes = [] def post(self,requeset): ......
全局使用实例
REST_FRAMEWORK = { 'DEFAULT_PARSER_CLASSES':[ 'rest_framework.parsers.JSONParser' # 'rest_framework.parsers.FormParser' # 'rest_framework.parsers.MultiPartParser' ], "DEFAULT_AUTHENTICATION_CLASSES":["app01.views.myAuthen",] }
token不存数据库方式,请参照
原文链接:https://www.cnblogs.com/liuqingzheng/articles/9766397.html
def get_token(id,salt='123'): import hashlib md=hashlib.md5() md.update(bytes(str(id),encoding='utf-8')) md.update(bytes(salt,encoding='utf-8')) return md.hexdigest()+'|'+str(id) def check_token(token,salt='123'): ll=token.split('|') import hashlib md=hashlib.md5() md.update(bytes(ll[-1],encoding='utf-8')) md.update(bytes(salt,encoding='utf-8')) if ll[0]==md.hexdigest(): return True else: return False class TokenAuth(): def authenticate(self, request): token = request.GET.get('token') success=check_token(token) if success: return else: raise AuthenticationFailed('认证失败') def authenticate_header(self,request): pass class Login(APIView): def post(self,reuquest): back_msg={'status':1001,'msg':None} try: name=reuquest.data.get('name') pwd=reuquest.data.get('pwd') user=models.User.objects.filter(username=name,password=pwd).first() if user: token=get_token(user.pk) # models.UserToken.objects.update_or_create(user=user,defaults={'token':token}) back_msg['status']='1000' back_msg['msg']='登录成功' back_msg['token']=token else: back_msg['msg'] = '用户名或密码错误' except Exception as e: back_msg['msg']=str(e) return Response(back_msg) from rest_framework.authentication import BaseAuthentication class TokenAuth(): def authenticate(self, request): token = request.GET.get('token') token_obj = models.UserToken.objects.filter(token=token).first() if token_obj: return else: raise AuthenticationFailed('认证失败') def authenticate_header(self,request): pass class Course(APIView): authentication_classes = [TokenAuth, ] def get(self, request): return HttpResponse('get') def post(self, request): return HttpResponse('post')
二、rest=framework之权限组件
作用:校验用户是否有权限访问
因为是在认证通过才执行的,所以可以取出user
创建类
class User(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) pwd=models.CharField(max_length=32,null=True) mychoice=((1,'普通用户'),(2,'超级用户'),(3,'宇宙用户')) usertyle=models.IntegerField(choices=mychoice,default=1)
2.1)定义权限组件
# 权限组件 class myPermission(): message = '不是超超级用户,查看不了' def has_permission(self,request,view): print(request.user.usertype) if request.user.usertype !=3: return False else: return True
使用和认证组件的方法一样,只是要写在认证组件之后
from app01 import myserial from app01.auth import myPermission class Book(APIView): authentication_classes = [myAuthen,] permission_classes = [myPermission,] def get(self,request): response = MyResponse() # print(request.user.name) # 打印用户 # print(request.auth.token) # 携带的token books=models.Book.objects.all() ret = myserial.BookSer(instance=books,many=True) response.msg = '查询成功' response.data=ret.data return JsonResponse(response.get_dic,safe=False)
2.2)继承权限:from rest_framework.permissions import BasePermission
from rest_framework.permissions import BasePermission class myPermission(BasePermission): message = '不是超超级用户,查看不了' def has_permission(self,request,view): print(request.user.usertype) if request.user.usertype !=1: return False else: return True