DRF
1.MD5和base64区别
base64 编码和解码
nd5长度固定 不可反解
base64 变长 可以反解
#base64编码
import base64
import json
dic={'name':'zzz','age':19}
dic_str=json.dumps(dic)
#使用base64编码必须是bytes类型 二进制
print(dic_str.encode('utf-8'))
ret=base64.b64encode(dic_str.encode('utf-8'))
print(ret)
#base64解码
tmp=base64.b64decode(ret)
print(tmp)
2、手写注册查询
#views视图类
from django.shortcuts import render
# Create your views here.
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import CreateModelMixin,RetrieveModelMixin,UpdateModelMixin
from apu import models
from apu import ser
#密码需要加密存入数据库,sava方法
class RegisterView(GenericViewSet,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin):
queryset = models.User.objects.all()
serializer_class =ser.UserSerializer
# 如果get请求和post请求用的序列化类不一样,如何处理
# 需要重写get_serializer_class 这个类返回什么用的序列化类就是什么
# 注册用的是RegisterView,查询用的是ListRetriveView
def get_serializer_class(self):
print(self.action) #只可能是create 或者retrieve
if self.action=='create':
return ser.UserSerializer
elif self.action=='retrieve':
return ser.ListSerializer
elif self.action=='update':
#上传文件要用formdata格式的
return ser.UserImageSerializer
#自定义序列化类
from rest_framework import serializers
from apu import models
from rest_framework.exceptions import ValidationError
class UserSerializer(serializers.ModelSerializer):
# 第二次输入密码 required:必填 write_only:只能写入数据 不会显示
re_password = serializers.CharField(max_length=16, min_length=4, required=True, write_only=True)
class Meta:
model = models.User
# icon 非必填 因为设置表时候指定了默认值 ,还可以加required=True,null=True 也可以不用填 其他必须填
fields = ['username', 'password', 're_password', 'mobile', 'icon']
extra_kwargs = {
'username': {'max_length': 16},
'password': {'write_only': True},
}
# 局部钩子 校验手机号
def validate_mobile(self, mobile):
if not len(mobile) == 11:
raise ValidationError('手机号必须是11位')
return mobile
# 全局钩子校验两次密码输入是否一致
def validate(self, attrs):
if not attrs.get('password') == attrs.get('re_password'):
raise ValidationError('两次密码不一致')
# 写入数据库不需要第二次输入的密码,因为数据库没有这个字段
attrs.pop('re_password')
return attrs
# 重写create
def create(self, validated_data):
user = models.User.objects.create_user(**validated_data)
return user
class ListSerializer(serializers.ModelSerializer):
class Meta:
model = models.User
fields = ['username', 'password', 'mobile', 'icon']
class UserImageSerializer(serializers.ModelSerializer):
class Meta:
model = models.User
fields = ['icon']
#urls总路由
from django.contrib import admin
from django.urls import path,include,re_path
from django.views.static import serve #django 内置的一个视图函数
from django.conf import settings #获取配置文件用这个 获取的多一点
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('apu.urls')),
#开发media文件夹
re_path('media/(?P<path>.*)', serve,{'document_root':settings.MEDIA_ROOT}),
]
#子路由
from django.contrib import admin
from django.urls import path,include
from rest_framework.routers import DefaultRouter,SimpleRouter
from apu import views
router=SimpleRouter()
router.register('register',views.RegisterView,'register')
# router.register('list',views.ListRetriveView,'list')
urlpatterns = [
# path('admin/', admin.site.urls),
# path('api/', include('apu.urls')),
]
urlpatterns += router.urls
#settings 修改的配置
# image指定这两个需要
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media') # 真正文件路径
AUTH_USER_MODEL = 'apu.user' #app名字.表名小写
3.jwt
1.#可以通过认证类:JSONWebTokenAuthentication 和权限类IsAuthenticated 控制用户必须登录才可以访问的接口
class OrderAPIView(APIView):
#jwt认证
authentication_classes = [JSONWebTokenAuthentication,]
#权限控制
permission_classes = [IsAuthenticated,]
def get(self,request,*args,**kwargs):
return Response('这是订单信息')
#如果用户不登录就可以访问的接口只需要设置JSONWebTokenAuthentication 把权限类IsAuthenticated去掉就ok了
class UserInfoAPIView(APIView):
#jwt认证
authentication_classes = [JSONWebTokenAuthentication,]
def get(self,request,*args,**kwargs):
return Response('UserInfoAPIView')
2.控制登录接口返回的数据格式
2.1第一种方案 自己写登录接口
2.2 第二种方案 用内置,控制返回数据格式
jwt的配置信息中
#响应数据的配置格式
'JWT_RESPONSE_PAYLOAD_HANDLER':
'rest_framework_jwt.utils.jwt_response_payload_handler',
#可以重写jwt_response_payload_handler来控制返回数据的格式
3.1重写jwt_response_payload_handler
#返回什么前端就能看到什么
def My_jwt_response_payload_handler(token, user=None, request=None):
return {
'token': token,
'msg':'登陆成功',
'status':100,
'username':user.username
}
#配置文件
#jwt配置
JWT_AUTH={
'JWT_RESPONSE_PAYLOAD_HANDLER':'app02.utils.My_jwt_response_payload_handler'
}
3.2测试结果
3.3自定义jwt的权限类
#下面这俩导入的都是restframework的BaseAuthentication,因为在jwt里面也导入了BaseAuthertication
from rest_framework.authentication import BaseAuthentication
# from rest_framework_jwt.authentication import BaseJSONWebTokenAuthentication
from rest_framework.exceptions import AuthenticationFailed
# from rest_framework_jwt.authentication import jwt_decode_handler
from rest_framework_jwt.utils import jwt_decode_handler #和上面一毛一样
#异常
import jwt
from apu import models
class MyJwtAuthentication(BaseAuthentication):
def authenticate(self, request):
jwt_value=request.META.get('HTTP_AUTHORIZATION')
if jwt_value:
#jwt 提供了通过三段token取出payload的方法,并且有校验功能
try:
payload=jwt_decode_handler(jwt_value)
except jwt.ExpiredSignature:
raise AuthenticationFailed('签名过期')
except jwt.InvalidTokenError:
raise AuthenticationFailed('非法用户')
except Exception as e:
raise AuthenticationFailed(str(e))
#因为payload他就是用户信息字典
print(payload)
# return payload, jwt_value
#需要得到user对象 第一种去数据库查
# user=models.User.objects.get(pk=payload.get('user_id'))
#第二种不查库
user=models.User(id=payload.get('user_id'),username=payload.get('username'))
return user,jwt_value
#没有值抛异常
raise AuthenticationFailed('你没有携带认证信息')
----------------------------
from rest_framework_jwt.authentication import BaseJSONWebTokenAuthentication
class MyJwtAuthentication(BaseJSONWebTokenAuthentication):
def authenticate(self, request):
jwt_value=request.META.get('HTTP_AUTHORIZATION')
if jwt_value:
#jwt 提供了通过三段token取出payload的方法,并且有校验功能
try:
payload=jwt_decode_handler(jwt_value)
except jwt.ExpiredSignature:
raise AuthenticationFailed('签名过期')
except jwt.InvalidTokenError:
raise AuthenticationFailed('非法用户')
except Exception as e:
raise AuthenticationFailed(str(e))
#因为payload他就是用户信息字典
print(payload)
#这个方法实际上内部也查询了数据库
user=self.authenticate_credentials(payload)
return user,jwt_value
#没有值抛异常
raise AuthenticationFailed('你没有携带认证信息')
3.4手动签发token
#为了用户的多登录方式
#views
from app02 import ser
#手动签发token 实现多方式登录
from rest_framework.viewsets import ViewSetMixin,ViewSet
class Login2View(ViewSet):
def login(self,request,*args,**kwargs):
print('hhhh')
#1.有一个序列化的类
#2.生成序列化对象
login_ser = ser.LoginModelSerializers(data=request.data,context={'request':request})
#3.调用序列化对象的is_validad
login_ser.is_valid(raise_exception=True)
token=login_ser.context.get('token')
#4.return
return Response({'status':100,'msg':'登录成功','token':token,'username':login_ser.context.get('username')})
#自定义序列化
from rest_framework import serializers
from apu import models
import re
from rest_framework.exceptions import ValidationError
# 签发token用到的
from rest_framework_jwt.utils import jwt_encode_handler, jwt_payload_handler
class LoginModelSerializers(serializers.ModelSerializer):
username = serializers.CharField()
class Meta:
model = models.User
fields = ['username', 'password']
def validate(self, attrs):
print(1)
print(self.context)
# 在这写逻辑
username = attrs.get('username')
password = attrs.get('password')
# 通过判断,username数据不同,查询的字段不一样
# 正则匹配,如果是手机号
if re.match('^1[3-9][0-9]{9}$', username):
print(2)
user = models.User.objects.filter(mobile=username).first()
elif re.match('^.+@.+$', username):
user = models.User.objects.filter(email=username).first()
else:
user = models.User.objects.filter(username=username).first()
if user: # 用户存在
# 校验密码,因为是密文 要用check_password
if user.check_password(password):
# 密码正确要签发token
payload = jwt_payload_handler(user) # user传入得到payload
token = jwt_encode_handler(payload) # payload传入得到token
self.context['token'] = token
self.context['username'] = username
return attrs
else:
raise ValidationError('密码错误')
else:
raise ValidationError('用户不存在')
#urls
path('login2/', views.Login2View.as_view({'post':'login'})),
3.5配置过期时间
import datetime
JWT_AUTH={
'JWT_RESPONSE_PAYLOAD_HANDLER':'app02.utils.My_jwt_response_payload_handler',
'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7),
}
4.基于角色的权限控制(django内置auth体系)
#RBAC 基于角色的访问控制,公司内部系统
#django 中
后台的权限控制(公司内部)
user表
permssion表
group表和
其中user_group表是user表和group表的中间表
group_permssion是group表和permssion表的中间表
user_permission是user表和permssion表的中间表
#前台主站 需要三大认证 认证 、权限、频率
5.django缓存
#前后端混合开发缓存的使用
缓存的位置,通过文件来操作(以文件为例)
缓存的粒度
settings.py文件配置
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', #指定缓存使用的引擎
'LOCATION': '/var/tmp/django_cache', #指定缓存的路径
'TIMEOUT':300, #缓存超时时间(默认为300秒,None表示永不过期)
'OPTIONS':{
'MAX_ENTRIES': 300, # 最大缓存记录的数量(默认300)
'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
}
}
}
全站缓存
中间件
MIDDLEWARE_CLASSES = (
‘django.middleware.cache.UpdateCacheMiddleware’, #第一
......
‘django.middleware.cache.FetchFromCacheMiddleware’, #最后
)
-页面缓存
在试图上添加装饰器
from django.views.decorators.cache import cache_page
@cache_page(5) #缓存五秒钟
def test_cache(request):
pass
-面局部缓存
{% load cache %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% cache 2 'name' %} #表示缓存2秒钟, name是唯一key值
<h3>缓存:-----:{{ t }}</h3>
{% endcache %}
</body>
</html>
#前后的分离缓存的使用
from django.core.cache import cache
def test(request):
#set可以放对象,字符串
cache.set('name','zhang') #通过set、get获取缓存 前面是key 后面是value value可以是任意数据类型
# 应用场景
第一次查询所有图书。通过多表联合查询序列化的数据,直接缓存起来
然后以后再去缓存查询,如果有直接返回 没有再去数据库查询 然后在缓存