1、rest framework的版本使用git
一、版本能够写在URL中,经过GET传参,如 http://127.0.0.1:8082/api/users/?version=v1django
(1)自定义类获取版本信息:json
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)
(2)经过内置类来获取版本api
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)
在项目的settings中进行参数配置:app
二、也能够写在URL的路径中,如 http://127.0.0.1:8082/api/v1/users/ide
能够经过内置类来获取:函数
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)
推荐使用第二种方法来配置版本信息。post
三、能够将版本类写到配置文件中,进行全局控制:ui
在项目的settings中进行设置:this
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)
四、源码流程
路由→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"), ]
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)
2、解析器
解析器:对请求体的数据进行解析
一、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有值。
二、rest framework的解析器
一、示例
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)
JSONParser类只能解析Content-type为applicaton/json的数据,
FormParser类只能解析Content-type为applicaton/x-www-form-urlencoded的数据,
三、rest framework的解析器源码流程
执行dispatch()中的initialize_request()方法:
在视图中调用requst.data触发:
request的data方法调用_load_data_and_files():
以JSONParser类为例:
3、rest framework序列化处理数据
一、示例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)
from django.conf.urls import url from api import views urlpatterns = [ url(r'^(?P<version>[v1|v2]+)/roles/$', views.RolesView.as_view()), ]
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)
二、序列化自定义字段
from django.conf.urls import url from api import views urlpatterns = [ url(r'^(?P<version>[v1|v2]+)/userInfo/$', views.UserInfoView.as_view()), ]
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)
三、除了继承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)
这种方式生成的数据比较”简陋“,能够根据需求定制:
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)
四、序列化深度控制
自动序列化实现连表操做
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)
五、序列化生成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"), ]
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)
六、序列化源码流程
若是是处理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()的时候要传递参数:
4、rest framework序列化验证用户请求数据
一、自定义类 验证用户请求数据
from django.conf.urls import url from api import views urlpatterns = [ url(r'^(?P<version>[v1|v2]+)/userGroup/$', views.UserGroupView.as_view()), ]
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")
二、源码
在Serializer类中实现了请求数据校验:
from django.conf.urls import url from api import views urlpatterns = [ url(r'^(?P<version>[v1|v2]+)/userGroup/$', views.UserGroupView.as_view()), ]
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")