djangorestframework技术文档 restfrmework规范
开发模式
普通开发为前端和后端代码放在一起写
前后端分离为前后端交互统统为ajax进行交互
前后端分离
优点:分工明细,节省开发周期。代码维护性强!
后端开发
为前端提供URL(API开发)
django FBV和CBV
FBV function base view CBV class base view
FBV
def student(request):
#代码片段
return HttpResponse('返回值')
CBV
views.py
class StudentView(object):
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('返回值')
urls.py
from django.conf.urls import url
urlpatterns = [
url(r'student/',views.StudentView.as_view()),
]
回顾
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 是对象列表
面向对象
-封装
封装体现在两大方面,第一方面是类可以对同一类方法进行封装,另一方面是将数据封装到对象中。
class File:
#文件的增删改查方法
class DB:
#数据库的增删改查方法
def get:
def post:
def update:
def delete:
class DB:
def get:
def post:
def update:
def delete:
### 将数据封装到对象中
class File:
def __init__(self,a1,a2):
self.a1 = a1
self.xxx = a2
def get:...
def post: ...
def update: ...
def add: ...
obj1 = File(123,456)
obj2 = File(456,789)
class Request(object):
def __init__(self,obj):
self.obj = obj
@property
def user(self):
return self.obj.aythticate()
class Auth(object):
def __init__(self,name,age):
self.name = name
self.age = age
def authticate(self):
return True
class APIView(object):
def dispatch(self):
self.f2()
def f2(self):
a = Auth('alex',18)
req = Request(a)
print(req.user)
obj = APIView()
obj.dispatch()
把封装示例搞明白
http_method_names = ['get','post','put','delete','patch','head', 'options', 'trace'']
CBV:基于反射实现根据请求方式不同,执行不同的方法。
原理:
a.路由
url 对应 自定义的view函数 对应 dispatch方法(根据反射执行其他方法:GET/POST/PUT/DELETE.....)
继承(多个类共用的功能,为了避免重复编写,可以使用继承来实现。)
from django.views import View
class MyBaseView(object):
def dispatch(self,request,*args,**kwargs):
print('berfore')
ret = super(MyBaseView,self).dispatch(request,*args,**kwargs)
print('after')
return ret
class StudentView(MyBaseView,View):
def get(self,request,*args,**kwargs):
print('get方法')
return HttpResponse('GET')
def post(self,request,*args,**kwargs):
print('POST方法')
return HttpResponse('post')
def put(self,request,*args,**kwargs):
print('put方法')
return HttpResponse('put')
def delete(self,request,*args,**kwargs):
print('delete方法')
return HttpResponse('delete')
Django中间件
process_request
process_response
process_view
process_exception
process_render_template
Django的中间件就是上面这些,没有其他的了
小知识:
请求进来先执行中间件所有的process_request,通过process_request后进行路由匹配,路由匹配之后在执行process_view,process_view执行完执行视图函数,视图函数如果没有出错执行完毕执行process_response,如果报错执行 process_exception ,如果视图函数返回的对象中有render方法,那就process_render_template也会被执行。
使用中间件做过什么?
权限
用户登录验证
csrf_token
django的csrf是如何实现的?
csrf中间件写在process_view里面_ process_view方法 检查视图函去请求体或cookie中获取token数是否被@csrf_exempt(免除csrf认证) 去请求体或cookie中获取token
如何让函数免除csrf_token验证?
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def a():
pass
如何让函数需要csrf_token认证?
settings.py中的csrf中间件认证被注释
视图函数需要csrf_token认证
from django.views.decorators.csrf import csrf_protect
@csrf_protect
def user():
pass
CBV特殊的东西! 如果想给cbv加上csrf_token csrf时需要使用 -@method_decorator(csrf_exempt) -在dispatch方法上加上(单独的方法加上无效)
方法示例一:
views.py
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
class Student(View):
@method_decorator(csrf_exempt)
def dispatch(self,request,*args,**kwargs):
return super(StudentView,self).dispatch(self,*args,**kwargs)
def get(self,request,*args,**kwargs):
pass
def post(self,request,*args,**kwargs):
pass
方法示例二:
views.py
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
@method_decorator(csrf_exempt,name='dispatch')
class Student(View):
def dispatch(self,request,*args,**kwargs):
return super(StudentView,self).dispatch(self,*args,**kwargs)
def get(self,request,*args,**kwargs):
pass
def post(self,request,*args,**kwargs):
pass
总结:
CBV 本质
基于用户请求的方法和反射实现的
CBV 流程
请求 ---- 路由 ---- view ---- dispatch(反射)
取消csrf认证(装饰器要加到dispatch方法上)
,且method_decorator装饰)
扩展
-csrf
- 基于中间件实现(process_view方法)
- 基于装饰器给单独函数进行设置(认证或无需认证)
restful 规范(建议)
根据method不同做不同的操作
示例(FBV):
urlpatterns = [
url(
'order/',views.order
)
]
def order(request):
if request.method =='GET':
pass
if request.method =='POST':
pass
if request.method =='PUT':
pass
if request.method =='DELETE':
pass
示例(CBV):
urlpatterns = [
url(
'order/',views.OrderView.as_view()
)
]
class OrderView(View):
def get(self,request,*args,**kwargs):
pass
def post(self,request,*args,**kwargs):
pass
def put(self,request,*args,**kwargs):
pass
def delete(self,request,*args,**kwargs):
pass
restful规范(10个规范) API与用户的通信协议,总是使用HTTPS协议. 域名:https://api.example.com #尽量将API于.
子域名方式
www.luffycity.com
api.luffycity.com
URL方式
www.luffycity.com
www.luffycity.com/api/
使用子域名的时候容易出现跨域 域名不同或者端口不同都会出现跨域
使用URL的方式就不会出现跨域问题
版本
url :https://api.example.com/v1/
请求头
跨域时,引发发送多次请求
路径:视网络上任何东西都是资源,均使用名词表示(可复数)
https://api/example.com/v1/zooms/
method GET 从服务器取出资源(一项或多项)
POST 在服务器新建一个资源
PUT 在服务器更新紫云(客户端提供改变后的完整资源)
PATCH 在服务器更新资源(客户端提供改变的属性)
DELETE 从服务器删除资源
过滤 通过url上传参数的形式传递搜索条件 http://api/example/v1/zooms/?limit=10 指定返回记录的数量
状态码 常用状态码列表 200 成功 201 用户新建或修改数据成功 202 Accepted 表示一个请求已经进入后台排队(异步任务) 204 用户删除数据成功
301 永久重定向
302 临时重定向
400 用户发出分请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的
401 表示用户没有权限(令牌,用户名,密码错误)
403 Forbiden 表示用户得到授权 ,但是访问被禁止的
404 用户发出的请求针对是不存在的记录,服务器没有及逆行操作,该操作是幂等的
406 用户请求的格式不可得,(比如用户请求json格式,但是只有xml格式)
410 Gone 用户请求的资源被永久删除,且不会再得到
422 当创建一个对象时,发生一个验证错误
500 服务器错误
状态码(status code)和code结合使用。
ret = {
"code":1000,
"msg":"xxx"
}
错误处理
{
"error":"xxx",
}
Hypermedia API result API 最好做到Hypermedia 即返回结果中提供链接,联向其他API方法,使得用户不查询 就能知道下一步怎么做
{
"link":{
"id":1,
"name":"苹果",
"url":"https://api/example/order/1"
}
}
谈谈你对restful api 规范的认识 伪装成老手讲故事:
其实本质上就是一种规范,是可以让我们根据规范更好的对API进行处理,更容易让前端记住URL 节约的URL的数量
django rest framework 框架
安装
pip install djangorestframework
继承
views.py
from rest_framework.views import APIView
class DogView(APIView):
def get(self,request,*args,**kwargs):
pass
def post(self,request,*args,**kwargs):
pass
def put(self,request,*args,**kwargs):
pass
rest framework CBV 执行APIView里的dispatch方法
认证 仅适用认证:
views.py
class DogView(APIView):
authentication_class = [MyAuthentication,]
csrf_token实现原理 用户发送get请求 后端生成TOKEN返回给用户,用户下次请求的时候必须携带后端返回的TOKEN
为了验证token,restframework已经帮我们做好了
class Authtication(object):
token = request.__request.GET.get('token')
token_obj = models.UserToken.objects.filter(token=token).first
if not token_obj:
raise exceptions.AuthenticationFailed('用户认证失败')
return (token_obj.user,token_obj)
class OrderView(APIView):
authentication_classes = [Authtication,]
def get(self,request,*args,**kwargs):
restframework支持认证全局配置
认证流程原理
认证可以在项目开发的settings.py下设置
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES":[],
"UNAUTHENTICATED_USER":[],
"UNAUTHENTICATED_TOKEN":[],
}
如果需要使用自己写的认证类,就在对应的[]增加自己写的类的路径,把路径放在字符串里
在自己写认证类的时候,自己的认证类必须继承 restframework 的BaseAuthentication, 因为 restframework里的BaseAuthentication里有个函数写的是默认报错!
内置认证类
1.认证类 必须继承 from rest_framework.authentication import BaseAuthentication
2.其他认证类:BasicAuthentication,
BasicAuthentication认证流程 前端把用户密码经过base64加密之后以HTTP_AUTHORIZATION为键,加密后的用户名和密码为值,传给后端,后端用request.META.get('HTTP_AUTHORIZATION', b'')拿到键值对,并把数据交给BasicAuthentication.authenticate去处理和解密得到用户名密码 用户名密码是以:进行切片,索引0是用户名 索引1是密码 并进行一系列
restframework 提供了内置的认证类,丰富了认证方法 我们只要写认证类必须继承restframework的 baseAuthentication认证类 并在自己的类里重写authenticate方法
梳理:
1.使用
创建类:继承BaseAuthentication 实现 authenticate方法
返回值:
None:我不管了,下一个认证来执行
raise exceptions.AuthenticationFaild('用户认证失败')
局部使用
from rest_framework.authentication import BaseAuthentication,BasicAuthentication
class UserInfoView(APIView):
authentication_classes = [BasicAuthentication,]
def get(self,request,*args,**kwargs):
pass
全局使用
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES":[],
"UNAUTHENTICATED_USER":[],
"UNAUTHENTICATED_TOKEN":[],
}
认证组件源码流程:
-dispatch
-封装 request
-获取定义的认证类(全局/局部),通过列表生成式创建对象
-initial
perform_authentication
request.user(内部循环.....)
权限
-
权限 问题:不用视图不用权限可以访问
基本使用: 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) 源码流程: - 请求进来 进入到dispatch - 封装request - initial -认证 -权限 -把类读过来,列表生成式生成对象,循环每一个对象,执行他的has_permission方法 梳理: 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'] }
restframework节流
请求数据进行校验
QuerySet不能用HttpResponse返回给前端
QuerySet只能进行序列化处理后返回给前端
内容回顾
谈谈面向对象?
面向对象的三大特性!
封装
封装主要体现在类封装到对象中,把字段封装到对象个中!
封装的特性在代码中哪里使用过?
自定义分页的时候,把当前页的数据通过封装的方法
start_config封装
标准封装:
django restframework 源码中体现的就是对request的封装
标准继承:
多继承, 经典类 和新式类
将公共的功能放到基类中,让我们继承的时候可使用的方法多样化
多态:
鸭子模型: 只要听到鸭子呱呱叫,我就认为是鸭子,鹦鹉呱呱叫 我也认为是鸭子!
多态体现
class a:
def send():
pass
class b:
def send():
pass
class func(arg):
arg.send()
obj = a:
func(obj)
Django的生命周期: 一个请求首先经过wsgi ref模块 它是python的内置模块 wsgi 跟django没有任何关系! 只是django利用wsgi做了一个socket wsgi是干嘛的? wsgi与django应用之间的约束规范的一种协议 wsgiref是干嘛的? wsgiref是实现了wsgi协议的一个模块,模块本质:一个socket服务端 uwsgi在公司将项目部署的时候使用uwsgi
werkzug 实现了wsgi协议的一个模块,一个socket服务端
tornado 是实现wsfi协议到一个模块
web server 有两个参数 environ start_response响应参数
穿过所有的中间件后进行路由匹配
视图函数通过ORM拿取数据模板拿模板进行渲染 数据通过json返回给模板展现出来
视图里进行dispatch
完整的说法:
前端请求进来,通过 wsgi后,然后穿过所有的中间件进行路由匹配的时候先执行在函数里嵌套的as.view(),相当于执行了as.views里面的view内置函数!view函数里执行dispatch
为什么执行dispatch?
因为路由里的as_view帮我们做的
先执行请求的封装,认证 权限 节流 通过反射找到函数进行执行
中间件&装饰器 中间件用于统一做所有请求批量做操作方法要中间件来做
你用中间件做过什么?
认证(rbac)
权限(基于权限的用户控制)
csrf_token
csrf_token原理
第一次来的时候服务端给随机字符串,再来的时候把随机字符串带过来,服务端进行验证
session原理
请求进来将相关的数据交给服务端,服务端拿到数据取数据库去查
session里有 process_request和process_response方法
session也是基于中间件设计的
中间件的使用场景
基于角色的权限控制
用户认证
csrf 说原理
session 说原理
黑名单
日志记录
rest 框架原理
认证流程
请求进来 -dispatch -封装request
把所有的认证对象封装到了request 进入到perform_authentication 调用request.user
在request.user里面又调用我我们自己写的authentication方法
认证类里面有几个方法
一共两个方法
authenticate
authenticate_header
权限流程
请求进来-走dispatch 封装request 直接去列表生成式执行权限的方法
权限有几种方法
has_permission
节流流程
匿名的时候根据IP/代理唯一标识进行节流进行节流
通过类的获取表示get_ident的方法得到IP或者代理获取到
使用用户使用用户名进行节流
restframework 版本
自定义版本
URL中通过GET传参
views.py
class ParamVersion(object):
def determine_version(self,request,*args,**kwargs):
version = request.query_params.get('version')
return version
class UserView(APIView):
versioning_class = ParamVersion
def get(self,request,*args,**kwargs):
pass
使用restframework 版本写好的使用方法
在自己的settings里
在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('用户列表')
restframework 解析器
前戏: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
restframework 序列化(重要
)
序列化有两大功能 :
1.对请求数据的校验
2.对QuerySet验证
序列化demo
创建serializers.py文件
此demo只是入门级demo,一般开发的时候不是下面这种写法!
下面这种写法只是给刚接触restframework的朋友提供思路
下面的写法也可以实现项目中的需求
models.py
from django.db import models
class RoleModels(models.Model):
title = models.CharField(max_lentch=32,verbase_name='名称')
def __str__(self):
return self.title
class Meta:
db_table = 'Role'
verbose_name = verbose_name_plural = '角色'
serializers.py
from rest_framework.serializers import Serializer
from .models import RoleModels
class RoleSerializer(Serializer)
title = serializer.CharField()
class Meta:
model = RoleModels
fields = ('id', 'title')
views.py
from django.http import HttpResponse
from .serializers import RoleSerializer
from .models import RoleModels
from rest_framework.views import APIView
import json
class RolesView(APIView):
def get(self,request,*args,**kwargs):
roles = RoleModels.objects.all()
ser = RoleSerializer(instance=roles,many=True)
ret = json.dumps(ser.data,ensure_asii=False)
return HttpResponse(ret)
代码里序列化中的many=True 意思是 roles = models.RoleModels.objects.all() 这段代码
roles拿到的是多条数据 ,所以在序列化中
要使用many=True 如果我们要取单条数据的写法是 role = models.RoleModels.objects.all().first()
序列化中把many改为many=False
因为Django的ORM取到的数据是QuerySet
所以需要通过序列化才能把数据返回给前端,如果不进行序列化就把数据返回出去就会报错
方式2
models.py
from django.db import models
class UserInfoModels(models.Model):
user_type_choices = (
(1,'普通用户'),
(2,'VIP'),
(3,'VVIP'),
)
user_type = models.IntegerField(choices=user_type_choices)
username = models.CharField(max_length=32,unique=True)
password = models.CharField(max_length=64)
Roles = models.ManyToManyField("Role")
def __str__(self):
return self.username
class Meta:
db_table = 'UserInfo'
verbose_name = verbose_name_plural = '用户'
serializers.py
from rest_framework.serializers import Serializer
from .models import UserInfoModels
class UserInfoSerializer(Serializer)
username = serializer.CharField()
password = serializer.CharField()
class Meta:
model = UserInfoModels
fields = ('id', 'username','password')
views.py
from django.http import HttpResponse
from .serializers import UserInfoSerializer
from .models import UserInfoModels
from rest_framework.views import APIView
import json
class UserInfoView(APIView):
def get(self,request,*args,**kwargs):
users = UserInfoModels.Objects.all()
ser = UserInfoSerializer(instance=users,many=True)
ret = json.dumps(ser.data,ensure_asii=False)
return HttpResponse(ret)
知识点
如何将user_type 从数字 显示成中文,不要显示user_type的键,显示它的值
我们要在序列化中声明字段
models.py
from django.db import models
class UserInfoModels(models.Model):
user_type_choices = (
(1,'普通用户'),
(2,'VIP'),
(3,'VVIP'),
)
user_type = models.IntegerField(choices=user_type_choices)
username = models.CharField(max_length=32,unique=True)
password = models.CharField(max_length=64)
Roles = models.ManyToManyField("Role")
def __str__(self):
return self.username
class Meta:
db_table = 'UserInfo'
verbose_name = verbose_name_plural = '用户'
serializers.py
from rest_framework.serializers import Serializer
from .models import UserInfoModels
class UserInfoSerializer(Serializer)
xxxx = serializer.CharField(source="get_user_type_display")
username = serializer.CharField()
password = serializer.CharField()
class Meta:
model = UserInfoModels
fields = ('id', 'username','password','xxxx')
无论我们给这个字段起个xxxx的名字还是其他的名字 只要这个source是对的,就可以把中文展示出来,这里的get_user_type_display 之后get_ 和_display是固定的,中间的字段是你models里的字段,我们的UserInfoModels是不是有user_type这个字段,所以要写成get_user_type_display
如果你的models里的字段是oooo ,那就写get_oooo_display,如果是username 那就写get_username_display 希望看到这里你能明白
这个source也适用于Models中的ForeignKey,但是不适用于ManyToManyField
如果要必须要使用ManyToManyField,我们只能在序列化中创建字段xxx = serializers.SerializerMethodField ,xxx是你models里ManyToManyField的字段名(这里只是演示说字段名是xxx)然后还需要在序列化下方定义一个函数
如果通过source取不到 用下面这个方法
serializer.py
#我们以角色表为例子
from rest_framework.serializers import Serializer
from .models import RoleModels
class RoleSerializer(Serializer)
title = serializer.CharField()
xxxx = serializerSerializerMethodField()
def get_xxxx(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
class Meta:
model = RoleModels
fields = ('id', 'title')
实际开发中我们会在序列化中引用ModelSerializer,很少使用Serializer
models.py
from django.db import models
class RoleModels(models.Model):
title = models.CharField(max_lentch=32,verbase_name='名称')
def __str__(self):
return self.title
class Meta:
db_table = 'Role'
verbose_name = verbose_name_plural = '角色'
serializers.py
from rest_framework.serializers import ModelSerializer
from .models import RoleModels
class RoleSerializer(ModelSerializer)
class Meta:
model = RoleModels
fields = ('__all__')
views.py
from django.http import HttpResponse
from .serializers import RoleSerializer
from .models import RoleModels
from rest_framework.views import APIView
import json
class RolesView(APIView):
def get(self,request,*args,**kwargs):
roles = RoleModels.objects.all()
ser = RoleSerializer(instance=roles,many=True)
ret = json.dumps(ser.data,ensure_asii=False)
return HttpResponse(ret)
部分总结:
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
自动序列化连表
class UserInfoSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = ("__all__")
# fields=['id','use**rname','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('提交数据')
restframework 分页
分页,看第n页,每页显示n条数据;
分页,看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)
restframework 路由系统
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'})),
restframework视图
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)
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
restframework 渲染器
在settings.py的INSTALLED_APPS 增加'rest_framework'
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',
]
}