s7day128
内容回顾:
1. 开发模式
- 普通开发方式(前后端放在一起写)
- 前后端分离
2. 后端开发
为前端提供URL(API/接口的开发)
注:永远返回HttpResponse
3. Django FBV、CBV
FBV,function base view
def users(request):
user_list = ['alex','oldboy']
return HttpResponse(json.dumps((user_list)))
CBV,class base view
路由:
url(r'^students/', views.StudentsView.as_view()),
视图:
from django.views import View
class StudentsView(View):
def get(self,request,*args,**kwargs):
return HttpResponse('GET')
def post(self, request, *args, **kwargs):
return HttpResponse('POST')
def put(self, request, *args, **kwargs):
return HttpResponse('PUT')
def delete(self, request, *args, **kwargs):
return HttpResponse('DELETE')
4. 列表生成时
class Foo:
pass
class Bar:
pass
v = []
for i in [Foo,Bar]:
obj = i()
v.append(obj)
v = [item() for item in [Foo,Bar]]
v对象列表
5. 面向对象
- 封装
- 对同一类方法封装到类中
class File:
文件增删改查方法
Class DB:
数据库的方法
- 将数据封装到对象中
class File:
def __init__(self,a1,a2):
self.a1 = a1
self.xxx = a2
def get:...
def delete:...
def update:...
def add:...
obj1 = File(123,666)
obj2 = File(456,999)
PS: 扩展
class Request(object):
def __init__(self,obj):
self.obj = obj
@property
def user(self):
return self.obj.authticate()
class Auth(object):
def __init__(self,name,age):
self.name = name
self.age = age
def authticate(self):
return self.name
class APIView(object):
def dispatch(self):
self.f2()
def f2(self):
a = Auth('alex',18)
b = Auth('oldboy',18)
req = Request(b)
print(req.user)
obj = APIView()
obj.dispatch()
今日概要:
1. restful 规范(建议)
2. django rest framework框架
内容详细:
0. FBV、CBV
CBV,基于反射实现根据请求方式不同,执行不同的方法。
原理:
url -> view方法 -> dispatch方法(反射执行其他:GET/POST/DELETE/PUT)
流程:
class StudentsView(View):
def dispatch(self, request, *args, **kwargs):
print('before')
ret = super(StudentsView,self).dispatch(request, *args, **kwargs)
print('after')
return ret
def get(self,request,*args,**kwargs):
return HttpResponse('GET')
def post(self, request, *args, **kwargs):
return HttpResponse('POST')
def put(self, request, *args, **kwargs):
return HttpResponse('PUT')
def delete(self, request, *args, **kwargs):
return HttpResponse('DELETE')
继承(多个类共用的功能,为了避免重复编写):
from django.views import View
class MyBaseView(object):
def dispatch(self, request, *args, **kwargs):
print('before')
ret = super(MyBaseView,self).dispatch(request, *args, **kwargs)
print('after')
return ret
class StudentsView(MyBaseView,View):
def get(self,request,*args,**kwargs):
print('get方法')
return HttpResponse('GET')
def post(self, request, *args, **kwargs):
return HttpResponse('POST')
def put(self, request, *args, **kwargs):
return HttpResponse('PUT')
def delete(self, request, *args, **kwargs):
return HttpResponse('DELETE')
class TeachersView(MyBaseView,View):
def get(self,request,*args,**kwargs):
return HttpResponse('GET')
def post(self, request, *args, **kwargs):
return HttpResponse('POST')
def put(self, request, *args, **kwargs):
return HttpResponse('PUT')
def delete(self, request, *args, **kwargs):
return HttpResponse('DELETE')
面试题:
1. django中间件
- process_request
- process_view
- process_response
- process_exception
- process_render_template
2. 使用中间件做过什么?
- 权限
- 用户登录验证
- django的csrf是如何实现?
process_view方法
- 检查视图是否被 @csrf_exempt (免除csrf认证)
- 去请求体或cookie中获取token
3.
情况一:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', # 全站使用csrf认证
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt # 该函数无需认证
def users(request):
user_list = ['alex','oldboy']
return HttpResponse(json.dumps((user_list)))
情况二:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
#'django.middleware.csrf.CsrfViewMiddleware', # 全站不使用csrf认证
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
from django.views.decorators.csrf import csrf_exempt
@csrf_protect # 该函数需认证
def users(request):
user_list = ['alex','oldboy']
return HttpResponse(json.dumps((user_list)))
CBV小知识,csrf时需要使用
- @method_decorator(csrf_exempt)
- 在dispatch方法中(单独方法无效)
方式一:
from django.views.decorators.csrf import csrf_exempt,csrf_protect
from django.utils.decorators import method_decorator
class StudentsView(View):
@method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
return super(StudentsView,self).dispatch(request, *args, **kwargs)
def get(self,request,*args,**kwargs):
print('get方法')
return HttpResponse('GET')
def post(self, request, *args, **kwargs):
return HttpResponse('POST')
def put(self, request, *args, **kwargs):
return HttpResponse('PUT')
def delete(self, request, *args, **kwargs):
return HttpResponse('DELETE')
方式二:
from django.views.decorators.csrf import csrf_exempt,csrf_protect
from django.utils.decorators import method_decorator
@method_decorator(csrf_exempt,name='dispatch')
class StudentsView(View):
def get(self,request,*args,**kwargs):
print('get方法')
return HttpResponse('GET')
def post(self, request, *args, **kwargs):
return HttpResponse('POST')
def put(self, request, *args, **kwargs):
return HttpResponse('PUT')
def delete(self, request, *args, **kwargs):
return HttpResponse('DELETE')
总结:
- 本质,基于反射来实现
- 流程:路由,view,dispatch(反射)
- 取消csrf认证(装饰器要加到dispatch方法上且method_decorator装饰)
扩展:
- csrf
- 基于中间件的process_view方法
- 装饰器给单独函数进行设置(认证或无需认证)
1. restful 规范(建议)
a. 接口开发
urlpatterns = [
# url(r'^admin/', admin.site.urls),
url(r'^get_order/', views.get_order),
url(r'^add_order/', views.add_order),
url(r'^del_order/', views.del_order),
url(r'^update_order/', views.update_order),
]
def get_order(request):
return HttpResponse('')
def add_order(request):
return HttpResponse('')
def del_order(request):
return HttpResponse('')
def update_order(request):
return HttpResponse('')
b. restful 规范(建议)
1. 根据method不同做不同的操作,示例:
基于FBV:
urlpatterns = [
url(r'^order/', views.order),
]
def order(request):
if request.method == 'GET':
return HttpResponse('获取订单')
elif request.method == 'POST':
return HttpResponse('创建订单')
elif request.method == 'PUT':
return HttpResponse('更新订单')
elif request.method == 'DELETE':
return HttpResponse('删除订单')
基于CBV:
urlpatterns = [
url(r'^order/', views.OrderView.as_view()),
]
class OrderView(View):
def get(self,request,*args,**kwargs):
return HttpResponse('获取订单')
def post(self,request,*args,**kwargs):
return HttpResponse('创建订单')
def put(self,request,*args,**kwargs):
return HttpResponse('更新订单')
def delete(self,request,*args,**kwargs):
return HttpResponse('删除订单')
c. 谈谈自己对restful api 规范的认识
10个规则
注意:推荐使用CBV
2. django rest framework框架
pip3 install djangorestframework
a. 认证
- 仅使用:
from django.views import View
from rest_framework.views import APIView
from rest_framework.authentication import BasicAuthentication
from rest_framework import exceptions
from rest_framework.request import Request
class MyAuthentication(object):
def authenticate(self,request):
token = request._request.GET.get('token')
# 获取用户名和密码,去数据校验
if not token:
raise exceptions.AuthenticationFailed('用户认证失败')
return ("alex",None)
def authenticate_header(self,val):
pass
class DogView(APIView):
authentication_classes = [MyAuthentication,]
def get(self,request,*args,**kwargs):
print(request)
print(request.user)
ret = {
'code':1000,
'msg':'xxx'
}
return HttpResponse(json.dumps(ret),status=201)
def post(self,request,*args,**kwargs):
return HttpResponse('创建Dog')
def put(self,request,*args,**kwargs):
return HttpResponse('更新Dog')
def delete(self,request,*args,**kwargs):
return HttpResponse('删除Dog')
- 源码流程:
dispatch...
作业:
1. 中间件
2. csrf
3. CBV
4. 规范
- 10条规范
- 认识
5. djangorestframework
- 如何验证(基于数据库实现用户认证)
- 源码流程(面向对象回顾流程)
预习:
版本
权限
控制访问频率
s7day129 内容回顾:
1. 中间件
2. csrf原理
3. rest 10规范
4. 面向对象
5. django请求声明周期
6. django请求声明周期(包含rest framework框架)
PS: dispatch
今日内容:
1. 认证
2. 权限
3. 节流(访问频率控制)
4. 版本
今日内容:
1. 认证
a. 问题1:有些API需要用户登录成功之后,才能访问;有些无需登录就能访问。
b. 基本使用认证组件
解决:
a. 创建两张表
b. 用户登录(返回token并保存到数据库)
c. 认证流程原理
- 见图示
d. 再看一遍源码
1. 局部视图使用&全局使用
2. 匿名是request.user = None
e. 内置认证类
1. 认证类,必须继承:from rest_framework.authentication import BaseAuthentication
2. 其他认证类:BasicAuthentication
梳理:
1. 使用
- 创建类:继承BaseAuthentication; 实现:authenticate方法
- 返回值:
- None,我不管了,下一认证来执行。
- raise exceptions.AuthenticationFailed('用户认证失败') # from rest_framework import exceptions
- (元素1,元素2) # 元素1赋值给request.user; 元素2赋值给request.auth
- 局部使用
from rest_framework.authentication import BaseAuthentication,BasicAuthentication
class UserInfoView(APIView):
"""
订单相关业务
"""
authentication_classes = [BasicAuthentication,]
def get(self,request,*args,**kwargs):
print(request.user)
return HttpResponse('用户信息')
- 全局使用:
REST_FRAMEWORK = {
# 全局使用的认证类
"DEFAULT_AUTHENTICATION_CLASSES":['api.utils.auth.FirstAuthtication','api.utils.auth.Authtication', ],
# "UNAUTHENTICATED_USER":lambda :"匿名用户"
"UNAUTHENTICATED_USER":None, # 匿名,request.user = None
"UNAUTHENTICATED_TOKEN":None,# 匿名,request.auth = None
}
2. 源码流程
- dispatch
- 封装request
- 获取定义的认证类(全局/局部),通过列表生成时创建对象。
- initial
- perform_authentication
request.user(内部循环....)
2. 权限
问题:不用视图不用权限可以访问
基本使用:
class MyPermission(object):
def has_permission(self,request,view):
if request.user.user_type != 3:
return False
return True
class OrderView(APIView):
"""
订单相关业务(只有SVIP用户有权限)
"""
permission_classes = [MyPermission,]
def get(self,request,*args,**kwargs):
# request.user
# request.auth
self.dispatch
ret = {'code':1000,'msg':None,'data':None}
try:
ret['data'] = ORDER_DICT
except Exception as e:
pass
return JsonResponse(ret)
源码流程:
- ...
梳理:
1. 使用
- 类,必须继承:BasePermission,必须实现:has_permission方法
from rest_framework.permissions import BasePermission
class SVIPPermission(BasePermission):
message = "必须是SVIP才能访问"
def has_permission(self,request,view):
if request.user.user_type != 3:
return False
return True
- 返回值:
- True, 有权访问
- False,无权访问
- 局部
class UserInfoView(APIView):
"""
订单相关业务(普通用户、VIP)
"""
permission_classes = [MyPermission1, ]
def get(self,request,*args,**kwargs):
return HttpResponse('用户信息')
- 全局
REST_FRAMEWORK = {
"DEFAULT_PERMISSION_CLASSES":['api.utils.permission.SVIPPermission']
}
2. 源码流程
3. 访问频率控制(节流)
问题:控制访问频率
import time
VISIT_RECORD = {}
class VisitThrottle(object):
"""60s内只能访问3次"""
def __init__(self):
self.history = None
def allow_request(self,request,view):
# 1. 获取用户IP
remote_addr = request.META.get('REMOTE_ADDR')
ctime = time.time()
if remote_addr not in VISIT_RECORD:
VISIT_RECORD[remote_addr] = [ctime,]
return True
history = VISIT_RECORD.get(remote_addr)
self.history = history
while history and history[-1] < ctime - 60:
history.pop()
if len(history) < 3:
history.insert(0,ctime)
return True
# return True # 表示可以继续访问
# return False # 表示访问频率太高,被限制
def wait(self):
"""
还需要等多少秒才能访问
:return:
"""
ctime = time.time()
return 60 - (ctime - self.history[-1])
class AuthView(APIView):
"""
用于用户登录认证
"""
authentication_classes = []
permission_classes = []
throttle_classes = [VisitThrottle,]
def post(self,request,*args,**kwargs):
ret = {'code':1000,'msg':None}
try:
user = request._request.POST.get('username')
pwd = request._request.POST.get('password')
obj = models.UserInfo.objects.filter(username=user,password=pwd).first()
if not obj:
ret['code'] = 1001
ret['msg'] = "用户名或密码错误"
# 为登录用户创建token
token = md5(user)
# 存在就更新,不存在就创建
models.UserToken.objects.update_or_create(user=obj,defaults={'token':token})
ret['token'] = token
except Exception as e:
ret['code'] = 1002
ret['msg'] = '请求异常'
return JsonResponse(ret)
源码流程:
...
内置控制频率类:
from rest_framework.throttling import BaseThrottle,SimpleRateThrottle
class VisitThrottle(SimpleRateThrottle):
scope = "Luffy"
def get_cache_key(self, request, view):
return self.get_ident(request)
class UserThrottle(SimpleRateThrottle):
scope = "LuffyUser"
def get_cache_key(self, request, view):
return request.user.username
REST_FRAMEWORK = {
# 全局使用的认证类
"DEFAULT_AUTHENTICATION_CLASSES":['api.utils.auth.FirstAuthtication','api.utils.auth.Authtication', ],
# "DEFAULT_AUTHENTICATION_CLASSES":['api.utils.auth.FirstAuthtication', ],
# "UNAUTHENTICATED_USER":lambda :"匿名用户"
"UNAUTHENTICATED_USER":None, # 匿名,request.user = None
"UNAUTHENTICATED_TOKEN":None,# 匿名,request.auth = None
"DEFAULT_PERMISSION_CLASSES":['api.utils.permission.SVIPPermission'],
"DEFAULT_THROTTLE_CLASSES":["api.utils.throttle.UserThrottle"],
"DEFAULT_THROTTLE_RATES":{
"Luffy":'3/m',
"LuffyUser":'10/m',
}
}
梳理:
a. 基本使用
- 类, 继承:BaseThrottle,实现:allow_request、wait
- 类, 继承:SimpleRateThrottle,实现:get_cache_key、scope = "Luffy"(配置文件中的key)
b. 局部
class AuthView(APIView):
"""
用于用户登录认证
"""
authentication_classes = []
permission_classes = []
throttle_classes = [VisitThrottle,] # *******************
def post(self,request,*args,**kwargs):
ret = {'code':1000,'msg':None}
try:
user = request._request.POST.get('username')
pwd = request._request.POST.get('password')
obj = models.UserInfo.objects.filter(username=user,password=pwd).first()
if not obj:
ret['code'] = 1001
ret['msg'] = "用户名或密码错误"
# 为登录用户创建token
token = md5(user)
# 存在就更新,不存在就创建
models.UserToken.objects.update_or_create(user=obj,defaults={'token':token})
ret['token'] = token
except Exception as e:
ret['code'] = 1002
ret['msg'] = '请求异常'
return JsonResponse(ret)
c. 全局
REST_FRAMEWORK = {
# 全局使用的认证类
"DEFAULT_AUTHENTICATION_CLASSES":['api.utils.auth.FirstAuthtication','api.utils.auth.Authtication', ],
# "DEFAULT_AUTHENTICATION_CLASSES":['api.utils.auth.FirstAuthtication', ],
# "UNAUTHENTICATED_USER":lambda :"匿名用户"
"UNAUTHENTICATED_USER":None, # 匿名,request.user = None
"UNAUTHENTICATED_TOKEN":None,# 匿名,request.auth = None
"DEFAULT_PERMISSION_CLASSES":['api.utils.permission.SVIPPermission'],
"DEFAULT_THROTTLE_CLASSES":["api.utils.throttle.UserThrottle"],
"DEFAULT_THROTTLE_RATES":{
"Luffy":'3/m',
"LuffyUser":'10/m',
}
}
今日作业: 昨天:
1. 中间件
2. csrf
3. CBV
4. 规范
- 10条规范
- 认识
5. djangorestframework
- 如何验证(基于数据库实现用户认证)
- 源码流程(面向对象回顾流程)
今天上午:
1. 中间件
2. csrf原理
3. rest 10规范
4. 面向对象
5. django请求声明周期
6. django请求声明周期(包含rest framework框架)
PS: dispatch
7. rest framework 认证流程(封装Request.user)
8. rest framework 权限流程
9. rest framework 节流流程
代码:
认证Demo,
权限Demo(用户类型不同,权限不同)
节流Demo(匿名,登录用)
三组件组合
s7day130
内容回顾:
1. 谈谈面向对象?
2. Django声明周期
a. wsgi
wsgi,是协议。
wsgiref,是实现了wsgi协议的一个模块。模块本质:一个socket服务端。(Django)
werkzeug ,是实现了wsgi协议的一个模块。模块本质:一个socket服务端(Flask框架)
tornado ,是实现了wsgi协议的一个模块。模块本质:一个socket服务端(Flask框架)
uwsgi,是实现了wsgi协议的一个模块。模块本质:一个socket服务端。
3. Django生命周期(rest framework)
4. 中间件&装饰器
- 适用于所有请求批量做操作
场景:
- 基于角色的权限控制
- 用户认证
- csrf,(说原理)
- session(说原理)
- 黑名单
- 日志记录
5. rest 框架原理
a. 认证流程
b. 权限
c. 节流
今日内容概要:
1. 版本 *
2. 解析器 *
3. 序列化 ****
- 请求数据进行校验
- QuerySet进行序列化
4. 分页 **
5. 路由 **
6. 视图 **
7. 渲染器 *
内容详细:
1. 版本
a. URL中通过GET传参()
自定义:
http://127.0.0.1:8000/api/users/?version=v2
class ParamVersion(object):
def determine_version(self, request, *args, **kwargs):
version = request.query_params.get('version')
return version
class UsersView(APIView):
versioning_class = ParamVersion
def get(self,request,*args,**kwargs):
#version = request._request.GET.get('version')
#print(version)
# version = request.query_params.get('version')
# print(version)
print(request.version)
return HttpResponse('用户列表')
b. 在URL中传参(推荐使用)
urlpatterns = [
# url(r'^admin/', admin.site.urls),
url(r'^(?P<version>[v1|v2]+)/users/$', views.UsersView.as_view()),
]
REST_FRAMEWORK = {
"DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",
"DEFAULT_VERSION":'v1',
"ALLOWED_VERSIONS":['v1','v2'],
"VERSION_PARAM":'version',
}
class UsersView(APIView):
def get(self,request,*args,**kwargs):
print(request.version)
return HttpResponse('用户列表')
总结:
使用:
配置文件:
REST_FRAMEWORK = {
"DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",
"DEFAULT_VERSION":'v1',
"ALLOWED_VERSIONS":['v1','v2'],
"VERSION_PARAM":'version',
}
路由系统:
urlpatterns = [
# url(r'^admin/', admin.site.urls),
url(r'^api/', include('api.urls')),
]
urlpatterns = [
# url(r'^admin/', admin.site.urls),
url(r'^(?P<version>[v1|v2]+)/users/$', views.UsersView.as_view(),name='uuu'),
]
视图:
class UsersView(APIView):
def get(self,request,*args,**kwargs):
# 1. 获取版本
print(request.version)
# 2. 获取处理版本的对象
print(request.versioning_scheme)
# 3. 反向生成URL(rest framework)
u1 = request.versioning_scheme.reverse(viewname='uuu',request=request)
print(u1)
# 4. 反向生成URL
u2 = reverse(viewname='uuu',kwargs={'version':2})
print(u2)
return HttpResponse('用户列表')
2. 解析器
前戏:django:request.POST/ request.body
1. 请求头要求:
Content-Type: application/x-www-form-urlencoded
PS: 如果请求头中的 Content-Type: application/x-www-form-urlencoded,request.POST中才有值(去request.body中解析数据)。
2. 数据格式要求:
name=alex&age=18&gender=男
如:
a. form表单提交
<form method...>
input...
</form>
b. ajax提交
$.ajax({
url:...
type:POST,
data:{name:alex,age=18} # 内部转化 name=alex&age=18&gender=男
})
情况一:
$.ajax({
url:...
type:POST,
headers:{'Content-Type':"application/json"}
data:{name:alex,age=18} # 内部转化 name=alex&age=18&gender=男
})
# body有值;POST无
情况二:
$.ajax({
url:...
type:POST,
headers:{'Content-Type':"application/json"}
data:JSON.stringfy({name:alex,age=18}) # {name:alex,age:18...}
})
# body有值;POST无
# json.loads(request.body)
rest_framework 解析器,对请求体数据进行解析
总结:
使用:
配置:
REST_FRAMEWORK = {
"DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",
"DEFAULT_VERSION":'v1',
"ALLOWED_VERSIONS":['v1','v2'],
"VERSION_PARAM":'version',
"DEFAULT_PARSER_CLASSES":['rest_framework.parsers.JSONParser','rest_framework.parsers.FormParser']
}
使用:
class ParserView(APIView):
# parser_classes = [JSONParser,FormParser,]
"""
JSONParser:表示只能解析content-type:application/json头
JSONParser:表示只能解析content-type:application/x-www-form-urlencoded头
"""
def post(self,request,*args,**kwargs):
"""
允许用户发送JSON格式数据
a. content-type: application/json
b. {'name':'alex',age:18}
:param request:
:param args:
:param kwargs:
:return:
"""
"""
1. 获取用户请求
2. 获取用户请求体
3. 根据用户请求头 和 parser_classes = [JSONParser,FormParser,] 中支持的请求头进行比较
4. JSONParser对象去请求体
5. request.data
"""
print(request.data)
return HttpResponse('ParserView')
源码流程 & 本质:
a. 本质
请求头 :...
状态码: ...
请求方法:...
b. 源码流程
- dispatch: request封装
- request.data
3. 序列化
序列化:
部分总结:
1. 写类
class RolesSerializer(serializers.Serializer):
id = serializers.IntegerField()
title = serializers.CharField()
class UserInfoSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
# fields = "__all__"
fields = ['id','username','password',]
2. 字段
a. title = serializers.CharField(source="xxx.xxx.xx.xx")
b. title = serializers.SerializerMethodField()
class UserInfoSerializer(serializers.ModelSerializer):
rls = serializers.SerializerMethodField() # 自定义显示
class Meta:
model = models.UserInfo
fields = ['id','username','password','rls',]
# 自定义方法
def get_rls(self, row):
role_obj_list = row.roles.all()
ret = []
for item in role_obj_list:
ret.append({'id':item.id,'title':item.title})
return ret
c. 自定义类
3. 自动序列化连表
class UserInfoSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
# fields = "__all__"
fields = ['id','username','password','group','roles']
depth = 1 # 0 ~ 10
4. 生成链接
class UserInfoSerializer(serializers.ModelSerializer):
group = serializers.HyperlinkedIdentityField(view_name='gp',lookup_field='group_id',lookup_url_kwarg='xxx')
class Meta:
model = models.UserInfo
# fields = "__all__"
fields = ['id','username','password','group','roles']
depth = 0 # 0 ~ 10
class UserInfoView(APIView):
def get(self,request,*args,**kwargs):
users = models.UserInfo.objects.all()
ser = UserInfoSerializer(instance=users,many=True,context={'request': request})
ret = json.dumps(ser.data, ensure_ascii=False)
return HttpResponse(ret)
源码:
对象, Serializer类处理;
QuerySet,ListSerializer类处理;
# ser.data
请求数据校验:
class XXValidator(object):
def __init__(self, base):
self.base = base
def __call__(self, value):
if not value.startswith(self.base):
message = '标题必须以 %s 为开头。' % self.base
raise serializers.ValidationError(message)
def set_context(self, serializer_field):
"""
This hook is called by the serializer instance,
prior to the validation call being made.
"""
# 执行验证之前调用,serializer_fields是当前字段对象
pass
class UserGroupSerializer(serializers.Serializer):
title = serializers.CharField(error_messages={'required':'标题不能为空'},validators=[XXValidator('老男人'),])
class UserGroupView(APIView):
def post(self,request,*args,**kwargs):
ser = UserGroupSerializer(data=request.data)
if ser.is_valid():
print(ser.validated_data['title'])
else:
print(ser.errors)
return HttpResponse('提交数据')
问: 自定义验证规则时,需要钩子函数?请问钩子函数如何写?
今日作业:
1. 今日内容
2. 序列化自定义钩子函数
s7day131
内容回顾:
1. rest规范
2. rest framework
- 要求:前4个组件
- 序列化
今日内容概要:
0. 序列化源码
1. 分页
a. 分页,看第n页,每页显示n条数据;
from rest_framework.pagination import PageNumberPagination
class MyPageNumberPagination(PageNumberPagination):
page_size = 2
page_size_query_param = 'size'
max_page_size = 5
page_query_param = 'page'
class Pager1View(APIView):
def get(self,request,*args,**kwargs):
# 获取所有数据
roles = models.Role.objects.all()
# 创建分页对象
# pg = MyPageNumberPagination()
pg = PageNumberPagination()
# 在数据库中获取分页的数据
pager_roles = pg.paginate_queryset(queryset=roles,request=request,view=self)
# 对数据进行序列化
ser = PagerSerialiser(instance=pager_roles, many=True)
return Response(ser.data)
# return pg.get_paginated_response(ser.data)
b. 分页,在n个位置,向后查看n条数据;
from api.utils.serializsers.pager import PagerSerialiser
from rest_framework.response import Response
from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination
class MyLimitOffsetPagination(LimitOffsetPagination):
default_limit = 2
limit_query_param = 'limit'
offset_query_param = 'offset'
max_limit = 5
class Pager1View(APIView):
def get(self,request,*args,**kwargs):
# 获取所有数据
roles = models.Role.objects.all()
# 创建分页对象
# pg = MyLimitOffsetPagination()
pg = LimitOffsetPagination()
# 在数据库中获取分页的数据
pager_roles = pg.paginate_queryset(queryset=roles,request=request,view=self)
# 对数据进行序列化
ser = PagerSerialiser(instance=pager_roles, many=True)
return Response(ser.data)
# return pg.get_paginated_response(ser.data)
c. 加密分页,上一页和下一页。
from api.utils.serializsers.pager import PagerSerialiser
from rest_framework.response import Response
from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination,CursorPagination
class MyCursorPagination(CursorPagination):
cursor_query_param = 'cursor'
page_size = 2
ordering = 'id'
page_size_query_param = None
max_page_size = None
class Pager1View(APIView):
def get(self,request,*args,**kwargs):
# 获取所有数据
roles = models.Role.objects.all()
# 创建分页对象
# pg = CursorPagination()
pg = MyCursorPagination()
# 在数据库中获取分页的数据
pager_roles = pg.paginate_queryset(queryset=roles,request=request,view=self)
# 对数据进行序列化
ser = PagerSerialiser(instance=pager_roles, many=True)
# return Response(ser.data)
return pg.get_paginated_response(ser.data)
总结:
1. 数据量大的话,如何做分页?
- 数据库性能相关?
2. 视图
a. 过去
class Pager1View(View):
pass
b. 现在
class Pager1View(APIView): # View
pass
c. 无用
from api.utils.serializsers.pager import PagerSerialiser
from rest_framework.generics import GenericAPIView
class View1View(GenericAPIView): # APIView
queryset = models.Role.objects.all()
serializer_class = PagerSerialiser
pagination_class = PageNumberPagination
def get(self,request,*args,**kwargs):
# 获取数据
roles = self.get_queryset() # models.Role.objects.all()
# [1, 1000,] [1,10]
pager_roles = self.paginate_queryset(roles)
# 序列化
ser = self.get_serializer(instance=pager_roles,many=True)
return Response(ser.data)
d. GenericViewSet(ViewSetMixin, generics.GenericAPIView):
路由:
url(r'^(?P<version>[v1|v2]+)/v1/$', views.View1View.as_view({'get': 'list'})),
视图:
from api.utils.serializsers.pager import PagerSerialiser
from rest_framework.viewsets import GenericViewSet
class View1View(GenericViewSet):
queryset = models.Role.objects.all()
serializer_class = PagerSerialiser
pagination_class = PageNumberPagination
def list(self, request, *args, **kwargs):
# 获取数据
roles = self.get_queryset() # models.Role.objects.all()
# [1, 1000,] [1,10]
pager_roles = self.paginate_queryset(roles)
# 序列化
ser = self.get_serializer(instance=pager_roles, many=True)
return Response(ser.data)
e.
路由系统:
url(r'^(?P<version>[v1|v2]+)/v1/$', views.View1View.as_view({'get': 'list','post':'create'})),
url(r'^(?P<version>[v1|v2]+)/v1/(?P<pk>\d+)/$', views.View1View.as_view({'get': 'retrieve','delete':'destroy','put':'update','patch':'partial_update'})),
视图:
from api.utils.serializsers.pager import PagerSerialiser
from rest_framework.viewsets import GenericViewSet,ModelViewSet
from rest_framework.mixins import ListModelMixin,CreateModelMixin
class View1View(ModelViewSet):
queryset = models.Role.objects.all()
serializer_class = PagerSerialiser
pagination_class = PageNumberPagination
PS: class View1View(CreateModelMixin,GenericViewSet):
总结:
a. 增删改查 ModelViewSet
b. 增删 CreateModelMixin,DestroyModelMixin GenericViewSet
c. 复杂逻辑 GenericViewSet 或 APIView
PS: 还债:
GenericAPIView.get_object
check_object_permissions
has_object_permission
3. 路由
a.
url(r'^(?P<version>[v1|v2]+)/parser/$', views.ParserView.as_view()),
b.
url(r'^(?P<version>[v1|v2]+)/v1/$', views.View1View.as_view({'get': 'list','post':'create'})),
c.
# http://127.0.0.1:8000/api/v1/v1/?format=json
url(r'^(?P<version>[v1|v2]+)/v1/$', views.View1View.as_view({'get': 'list','post':'create'})),
# http://127.0.0.1:8000/api/v1/v1.json
url(r'^(?P<version>[v1|v2]+)/v1\.(?P<format>\w+)$', views.View1View.as_view({'get': 'list','post':'create'})),
url(r'^(?P<version>[v1|v2]+)/v1/(?P<pk>\d+)/$', views.View1View.as_view({'get': 'retrieve','delete':'destroy','put':'update','patch':'partial_update'})),
url(r'^(?P<version>[v1|v2]+)/v1/(?P<pk>\d+)\.(?P<format>\w+)$', views.View1View.as_view({'get': 'retrieve','delete':'destroy','put':'update','patch':'partial_update'})),
d.
from api import views
from rest_framework import routers
router = routers.DefaultRouter()
router.register(r'xxxxx', views.View1View)
router.register(r'rt', views.View1View)
urlpatterns = [
url(r'^(?P<version>[v1|v2]+)/', include(router.urls)),
]
4. 渲染
from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer
class TestView(APIView):
# renderer_classes = [JSONRenderer,BrowsableAPIRenderer]
def get(self, request, *args, **kwargs):
# 获取所有数据
roles = models.Role.objects.all()
# 创建分页对象
# pg = CursorPagination()
pg = MyCursorPagination()
# 在数据库中获取分页的数据
pager_roles = pg.paginate_queryset(queryset=roles, request=request, view=self)
# 对数据进行序列化
ser = PagerSerialiser(instance=pager_roles, many=True)
return Response(ser.data)
REST_FRAMEWORK = {
"DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",
"DEFAULT_VERSION":'v1',
"ALLOWED_VERSIONS":['v1','v2'],
"VERSION_PARAM":'version',
"DEFAULT_PARSER_CLASSES":['rest_framework.parsers.JSONParser','rest_framework.parsers.FormParser'],
"PAGE_SIZE":2,
"DEFAULT_RENDERER_CLASSES":[
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
]
}
5. django组件:contenttype
今日作业:
1. 序列化
2. 视图继承流程
3. 写代码
a. vue
- 看到登录页面
- 数据用户名和密码,发送ajax请求
- 用户列表页面,将用户数据显示在页面中。
- 学生详细信息
b. django rest framework
- /auth/
返回token
- /students/(认证)
返回学生列表
- /students/\d+/
返回学生详细信息
c. 节流:
控制
- 匿名用户 2分钟10次
- 正常用户 2分钟20次
PS:
CORS