django的rest framework框架——版本、解析器、序列化
一、rest framework的版本使用
1、版本可以写在URL中,通过GET传参,如 http://127.0.0.1:8082/api/users/?version=v1
(1)自定义类获取版本信息:
from django.http import JsonResponse
from rest_framework.views import APIView 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):
res = {"code": 1000, "msg": None, "data": None}
version = request.version
print(version)
return JsonResponse(res)
views.py
(2)通过内置类来获取版本
from django.http import JsonResponse
from rest_framework.views import APIView
from rest_framework.versioning import QueryParameterVersioning class UsersView(APIView):
"""用户中心"""
versioning_class = QueryParameterVersioning # 获取版本信息 def get(self, request, *args, **kwargs):
res = {"code": 1000, "msg": None, "data": None}
version = request.version
print(version)
return JsonResponse(res)
views.py
在项目的settings中进行参数配置:
2、也可以写在URL的路径中,如 http://127.0.0.1:8082/api/v1/users/
可以通过内置类来获取:
from django.http import JsonResponse
from rest_framework.views import APIView
from rest_framework.versioning import URLPathVersioning class UsersView(APIView):
"""用户中心"""
versioning_class = URLPathVersioning # 获取版本信息 def get(self, request, *args, **kwargs):
res = {"code": 1000, "msg": None, "data": None}
version = request.version
print(version)
return JsonResponse(res)
views.py
推荐使用第二种方法来配置版本信息。
3、可以将版本类写到配置文件中,进行全局控制:
在项目的settings中进行设置:
from django.http import JsonResponse
from rest_framework.views import APIView class UsersView(APIView):
"""用户中心""" def get(self, request, *args, **kwargs):
res = {"code": 1000, "msg": None, "data": None}
version = request.version # 获取版本
print(version)
return JsonResponse(res)
views.py
4、源码流程
路由→as_view()→rest framework的dispatch()→initial()→determine_version()
可以通过request.version获取版本信息
通过request.versioning_scheme获取处理版本的对象,可以利用这个对象调用reverse()方法来反向生成url:
from django.conf.urls import url
from api import views urlpatterns = [
url(r'^(?P<version>[v1|v2]+)/users/$', views.UsersView.as_view(), name="userView"),
]
urls.py
from django.http import JsonResponse
from rest_framework.views import APIView class UsersView(APIView):
"""用户中心""" def get(self, request, *args, **kwargs):
res = {"code": 1000, "msg": None, "data": None}
version = request.version # 获取版本
scheme = request.versioning_scheme # 处理版本的对象 # 反向生成URL
url = scheme.reverse(viewname="userView", request=request)
print(url) return JsonResponse(res)
views.py
二、解析器
解析器:对请求体的数据进行解析
1、Django的解析器
from django.core.handlers.wsgi import WSGIRequest
在Django内部会跟据不同的情况将request.body里面的数据解析到request.POST:
所以只有当 Content_type='application/x-www-form-urlencoded' 时,才会去解析request.body里面的数据,另外,数据格式必须是 name=amy&age=18 这种格式才能被解析,
基于如上两个条件才能使得request.POST有值。
2、rest framework的解析器
1、示例
from django.http import JsonResponse
from rest_framework.views import APIView
from rest_framework.parsers import JSONParser class ExampleView02(APIView):
""""""
parser_classes = [JSONParser] # 解析器类JSONParser:表示允许用户发送json格式的数据{"name":"amy", "age":18} def post(self, request, *args, **kwargs):
res = {"code": 1000, "msg": None, "data": None}
data = request.data # 获取解析后的数据 res["data"] = data
return JsonResponse(res)
views.py
JSONParser类只能解析Content-type为applicaton/json的数据,
FormParser类只能解析Content-type为applicaton/x-www-form-urlencoded的数据,
3、rest framework的解析器源码流程
执行dispatch()中的initialize_request()方法:
- 全局解析器配置:
- 视图中配置:
在视图中调用requst.data触发:
request的data方法调用_load_data_and_files():
以JSONParser类为例:
三、rest framework序列化处理数据
1、示例1 序列化类的使用
from django.db import models class UserGroup(models.Model):
title = models.CharField(max_length=32) class UserInfo(models.Model):
user_type_choices = (
(1, "普通用户"),
(2, "vip"),
(3, "svip"),
)
user_type = models.IntegerField(choices=user_type_choices)
username = models.CharField(max_length=32, unique=True)
password = models.CharField(max_length=64)
group = models.ForeignKey(to="UserGroup", on_delete=models.CASCADE, null=True, blank=True)
roles = models.ManyToManyField(to="Role", blank=True) class UserToken(models.Model):
user = models.OneToOneField(to="UserInfo")
token = models.CharField(max_length=64) class Role(models.Model):
title = models.CharField(max_length=32) class Order(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
price = models.DecimalField(max_digits=5, decimal_places=2)
create_time = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(to="UserInfo", on_delete=models.CASCADE, null=True, blank=True)
models.py
from django.conf.urls import url
from api import views urlpatterns = [
url(r'^(?P<version>[v1|v2]+)/roles/$', views.RolesView.as_view()),
]
api/urls.py
import json from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from rest_framework import serializers from api import models class RolesSerializer(serializers.Serializer):
"""对获取的数据进行序列化操作"""
# 要与数据表中的字段向对应
id = serializers.CharField()
title = serializers.CharField() class RolesView(APIView):
"""获取角色""" def get(self, request, *args, **kwargs): # 方法一:
# roles = models.Role.objects.all().values("id", "title")
# roles = list(roles)
# res = json.dumps(roles, ensure_ascii=False) # 方法二:使用序列化类
# roles = models.Role.objects.all()
# # 实例化序列化类 如果是对多条数据进行序列化要设置 many=True
# serl = RolesSerializer(instance=roles, many=True)
# res = serl.data # 获取序列化后的结果
# res = json.dumps(res, ensure_ascii=False) role = models.Role.objects.all().first()
# 实例化序列化类 如果是对一条数据进行序列化要设置 many=False
serl = RolesSerializer(instance=role, many=False)
res = serl.data # 获取序列化后的结果
res = json.dumps(res, ensure_ascii=False) return HttpResponse(res)
views.py
2、序列化自定义字段
from django.conf.urls import url
from api import views urlpatterns = [
url(r'^(?P<version>[v1|v2]+)/userInfo/$', views.UserInfoView.as_view()),
]
urls.py
import json from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from rest_framework import serializers from api import models class UserInfoSerializer(serializers.Serializer):
"""对获取的数据进行序列化操作"""
username = serializers.CharField()
password = serializers.CharField()
user_type = serializers.CharField(source="get_user_type_display") # 获取choices字段的文本
group = serializers.CharField(source="group.title") # 获取ForeignKey字段
roles = serializers.SerializerMethodField() # 自定义显示ManyToMany字段 def get_roles(self, row):
"""获取角色对象信息"""
role_obj_list = row.roles.all()
res = []
for item in role_obj_list:
res.append({"id": item.id, "title": item.title})
return res class UserInfoView(APIView):
"""获取用户信息""" def get(self, request, *args, **kwargs):
users = models.UserInfo.objects.all()
serl = UserInfoSerializer(instance=users, many=True)
res = json.dumps(serl.data, ensure_ascii=False)
return HttpResponse(res)
views.py
3、除了继承Serializer类实现序列化,还可以使用ModelSerializer类来实现。ModelSerializer继承了Serializer
import json from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from rest_framework import serializers from api import models class UserInfoSerializer(serializers.ModelSerializer):
"""对获取的数据进行序列化操作"""
class Meta:
model = models.UserInfo
fields = "__all__" # 对所有的字段做序列化 class UserInfoView(APIView):
"""获取用户信息""" def get(self, request, *args, **kwargs):
users = models.UserInfo.objects.all()
serl = UserInfoSerializer(instance=users, many=True)
res = json.dumps(serl.data, ensure_ascii=False)
return HttpResponse(res)
views.py
这种方式生成的数据比较”简陋“,可以根据需求定制:
class UserInfoSerializer(serializers.ModelSerializer):
"""对获取的数据进行序列化操作"""
user_type = serializers.CharField(source="get_user_type_display")
group = serializers.CharField(source="group.title")
roles = serializers.SerializerMethodField() # 自定义显示ManyToMany字段 def get_roles(self, row):
"""获取角色对象信息"""
role_obj_list = row.roles.all()
res = []
for item in role_obj_list:
res.append({"id": item.id, "title": item.title})
return res class Meta:
model = models.UserInfo
fields = ["id", "username", "password", "user_type", "group", "roles"] class UserInfoView(APIView):
"""获取用户信息""" def get(self, request, *args, **kwargs):
users = models.UserInfo.objects.all()
serl = UserInfoSerializer(instance=users, many=True)
res = json.dumps(serl.data, ensure_ascii=False)
return HttpResponse(res)
views.py
4、序列化深度控制
自动序列化实现连表操作
class UserInfoSerializer(serializers.ModelSerializer):
"""对获取的数据进行序列化操作""" class Meta:
model = models.UserInfo
fields = "__all__"
depth = 1 # 深度控制 建议取0~10层,层数越多响应速度也会受到影响 class UserInfoView(APIView):
"""获取用户信息""" def get(self, request, *args, **kwargs):
users = models.UserInfo.objects.all()
serl = UserInfoSerializer(instance=users, many=True)
res = json.dumps(serl.data, ensure_ascii=False)
return HttpResponse(res)
views.py
5、序列化生成HyperMediaLink
需求:通过查看用户信息页面获取到查看分组信息的URL
from django.conf.urls import url
from api import views urlpatterns = [
url(r'^(?P<version>[v1|v2]+)/userInfo/$', views.UserInfoView.as_view()),
url(r'^(?P<version>[v1|v2]+)/group/(?P<pk>\d+)$', views.GroupView.as_view(), name="groupView"),
]
urls.py
import json from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from rest_framework import serializers from api import models class GroupSerializer(serializers.ModelSerializer):
"""对获取的数据进行序列化操作""" class Meta:
model = models.UserGroup
fields = "__all__" class UserInfoSerializer(serializers.ModelSerializer):
"""对获取的数据进行序列化操作"""
# 反向生成查看group的URL
group = serializers.HyperlinkedIdentityField(view_name="groupView", lookup_field="group_id", lookup_url_kwarg="pk") class Meta:
model = models.UserInfo
fields = ["id", "username", "password", "user_type", "group"] class GroupView(APIView):
"""获取分组信息""" def get(self, request, *args, **kwargs):
pk = kwargs.get("pk")
group_obj = models.UserGroup.objects.filter(id=pk).first()
serl = GroupSerializer(instance=group_obj, many=False)
res = json.dumps(serl.data, ensure_ascii=False)
return HttpResponse(res) class UserInfoView(APIView):
"""获取用户信息""" def get(self, request, *args, **kwargs):
users = models.UserInfo.objects.all()
serl = UserInfoSerializer(instance=users, many=True, context={"request": request})
res = json.dumps(serl.data, ensure_ascii=False)
return HttpResponse(res)
views.py
6、序列化源码流程
如果是处理QuerySet数据,就会执行many_init()方法:
相当于在内部,如果是处理对象(一条数据),就使用Serializer进行处理;如果是处理QuerySet(多条数据),就用ListSerializer处理。
实例化完成后,可以通过“对象名.data”方法 获取数据:
父类的data方法:
如果是处理对象(一条数据),就到Serializer类里面找to_representation()方法;如果是处理QuerySet(多条数据),就去ListSerializer里面找。
get_attribute()方法的具体实现:
循环字段列表获取字段对应的值:
获取instance对象对应的字段的属性值,然后把这个属性值赋值给instance,然后继续循环,直到instance从字段里面获取不到值为止,即取数据表中真正的数值,
如 UserInfo 表中有外键group,想要获取到group字段对应的表对象的title字段:group = serializers.CharField(source="group.title"),则此时attrs=['group', 'title'],
第一轮循环时:instance=getattr(UserInfo object,group)=UserGroup object,
第二轮循环时instance=getattr(UserGroup object,title)=A组,此时便通过外键获取到UserGroup表中的title字段的值了。
当字段是一个可以被调用的对象(如函数或方法)时,就在这个字段后面加上“()”,直接执行这个函数或者方法,将返回值赋值给instance。
如 获取一个choices字段的文本:user_type=serializers.CharField(source="get_user_type_display") ,这个get_user_type_display就是一个可调用的方法。
对于字段是serializers.HyperlinkedIdentityField()对象的时候执行的to_representation()方法:
所以,我们在使用HyperlinkedIdentityField()的时候要传递参数:
四、rest framework序列化验证用户请求数据
1、自定义类 验证用户请求数据
from django.conf.urls import url
from api import views urlpatterns = [
url(r'^(?P<version>[v1|v2]+)/userGroup/$', views.UserGroupView.as_view()),
]
urls.py
import json from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from rest_framework import serializers from api import models class MyValidator(object):
"""自定制校验规则"""
def __init__(self, base):
self.base = base def __call__(self, value):
# 设置一个必须以self.base开头的规则
if not value.startswith(self.base):
message = "this field must start with %s." % self.base
raise serializers.ValidationError(message) def set_context(self, serializer_field):
pass class UserGroupSerializer(serializers.Serializer):
title = serializers.CharField(
error_messages={"required": "标题不能为空"},
validators=[MyValidator("a-")],
) # 校验的字段:title class UserGroupView(APIView):
"""验证用户请求数据""" def post(self, request, *args, **kwargs):
# request.data :用户提交过来的数据
serl = UserGroupSerializer(data=request.data) # 如果请求数据是合法的,就获取到的数据,否则打印错误信息
if serl.is_valid():
print(serl.validated_data["title"])
else:
print(serl.errors)
return HttpResponse("xxx")
views.py
2、源码
在Serializer类中实现了请求数据校验:
from django.conf.urls import url
from api import views urlpatterns = [
url(r'^(?P<version>[v1|v2]+)/userGroup/$', views.UserGroupView.as_view()),
]
urls.py
from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from rest_framework import serializers
from api import models class UserGroupSerializer(serializers.Serializer):
title = serializers.CharField(
error_messages={"required": "标题不能为空"},
# validators=[MyValidator("a-")],
) # 校验的字段:title def validate_title(self, value):
"""自定义title字段钩子方法"""
if not value.startswith("a-"):
message = "值必须以'a-'开头."
raise serializers.ValidationError(message)
return value class UserGroupView(APIView):
"""验证用户请求数据""" def post(self, request, *args, **kwargs):
# request.data :用户提交过来的数据
serl = UserGroupSerializer(data=request.data) # 如果请求数据是合法的,就获取到的数据,否则打印错误信息
if serl.is_valid():
print(serl.validated_data["title"])
else:
print(serl.errors)
return HttpResponse("xxx")
views.py
django的rest framework框架——版本、解析器、序列化的更多相关文章
- 基于Django的Rest Framework框架的解析器
本文目录 一 解析器的作用 二 全局使用解析器 三 局部使用解析器 四 源码分析 回到目录 一 解析器的作用 根据请求头 content-type 选择对应的解析器对请求体内容进行处理. 有appli ...
- Django Rest framework 框架之解析器
解析器 序列化***** 请求数据进行校验 对queryset进行序列化处理 分页 路由 视图 渲染器
- python-django rest framework框架之解析器
1.解析器 : 对请求的数据进行解析 - 请求体进行解析. 解析器在你不拿请求体数据时 不会调用. class UsersView(APIView): def get(self,request,*ar ...
- ASP.NET在IIS7中如何更改网站的.net framework框架版本
IIS7安装好以后使用了.net 2.0 framework框架,经过折腾发现如下方法可以更改框架版本,从而可以部署使用其他版本框架开发的网站 方法一:建立网站时设置.net框架版本 方法二:对于已经 ...
- Django REST framework基础:解析器和渲染器
解析器 解析器的作用 解析器的作用就是服务端接收客户端传过来的数据,把数据解析成自己可以处理的数据.本质就是对请求体中的数据进行解析. 在了解解析器之前,我们要先知道Accept以及ContentTy ...
- Django之Rest Framework框架
一.什么是RESTful REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移” REST从资源的角度 ...
- django的rest framework框架——安装及基本使用
一.django的FBV 和 CBV 1.FBV(基于函数的视图): urlpatterns = [ url(r'^users/', views.users), ] def users(request ...
- Django笔记&教程 0-2 框架版本与相关工具
Django 自学笔记兼学习教程第0章第2节-- 框架版本与相关工具 点击查看教程总目录 1 版本 python: 3.6.5 Django: 2.2.11 (有些地方我也会对比下各种版本的区别) 安 ...
- $Django Rest Framework-频率组件,解析器
1 频率组件 #自定义组件写频率认证(重点继承BaseThrottle) from rest_framework.throttling import BaseThrottle import time ...
随机推荐
- centOS+uwsgi+nginx 部署flask项目,问题记录
用flask做的项目想要部署到centOS系统上,填了一些坑,终于成功了,记录一下遇到的问题: 此次部署主要是按照这个博客进行的 https://www.cnblogs.com/Ray-liang/p ...
- 551 Student Attendance Record I 学生出勤纪录 I
给定一个字符串来代表一个学生的出勤纪录,这个纪录仅包含以下三个字符: 'A' : Absent,缺勤 'L' : Late,迟到 'P' : Present,到场如果一个学生的出勤纪 ...
- MVC系列学习(十六)-区域的学习
1.查找控制器的过程 1.1调用其他项目中的控制器 a.先到网站根目录下的bin文件夹下,遍历所有的程序集 b.找到以Controller结尾的类 c.再找出其中继承了Controller的类 d.接 ...
- vue-quill-editor 富文本编辑器插件介绍
Iblog项目中博文的文本编辑器采用了vue-quill-editor插件,本文将简单介绍其使用方法. 引入配置 安装模块 npm install vue-quill-editor --save in ...
- 第4章 变量、作用域和内存---JS红宝书书摘系列笔记
一.基本类型和引用类型 ECMAScipt变量可能分为两种数据类型:基本类型和引用类型. 基本类型:指简单的数据段:包括Undefined.Null.Boolean.Number.String:可以操 ...
- Gitlab User Guide
Installation Configuration Set user name and email Add SSH keys Repository Create New Repository Clo ...
- SM2-DE
SM2单证书认证 下端 导入根证书以及通用证书[具有签名和加密证书的功能]和远端的证书[获取远端公钥信息] 1.配置证书域 crypto ca identity gernal exit 2.通过复制粘 ...
- A*算法研究
许多工业与科学计算问题都可以转化为在图中寻路问题.启发式的寻路方法将问题表示为一个图,然后利用问题本身的信息,来加速解的搜索过程.一个典型的例子是有一些通路连接若干城市,找出从指定起点城市到指定终点城 ...
- Mybatis Learning Notes 1
Mybatis Learning Notes 主要的参考是博客园竹山一叶的Blog,这里记录的是自己补充的内容 实体类属性名和数据库不一致的处理 如果是实体类的结果和真正的数据库的column的名称不 ...
- Android(java)学习笔记145:Handler消息机制的原理和实现
联合学习 Android 异步消息处理机制 让你深入理解 Looper.Handler.Message三者关系 1. 首先我们通过一个实例案例来引出一个异常: (1)布局文件activity_m ...