序列化, 分页,路由,视图,渲染器,版本,解析器,
一、版本
1.自定义get传参:
通过get方式传参拿到版本,通过自定义一个类, 然后重写determine_version
方法来实现,然后在视图中配置。
class ParamVersion(object):
def determine_version(self, request, *args, **kwargs):
# version = request._request.GET.get('version')
version = request.query_params.get('version')
return version
from rest_framework.versioning import BaseVersioning
class UserView(APIView):
versioning_class = ParamVersion
def get(self, request,*args, **kwargs):
print(request.version) # 这里就能拿到版本,通过get方式传参
return HttpResponse('用户列表')
2.通过get传参用rest框架来设置版本。
a.在settings中配置
REST_FRAMEWORK = {
'DEFAULT_VERSION': 'v1', # 默认版本
'ALLOWED_VERSIONS': ['v1', 'v2'], # 可支持版本
'VERSION_PARAM': 'version', # 参数
}
b. 在view视图中
from rest_framework.versioning import QueryParameterVersioning
class UserView(APIView):
versioning_class = QueryParameterVersioning
def get(self, request,*args, **kwargs):
print(request.version)
return HttpResponse('用户列表')
3.通过url传参
a、在url中通过正则匹配
urlpatterns = [
url(r'^(?P<version>[v1|v2]+)/users/$', views.UserView.as_view()),
]
b.在视图函数中
from rest_framework.versioning import URLPathVersioning
class UserView(APIView):
versioning_class = QueryParameterVersioning
def get(self, request,*args, **kwargs):
print(request.version)
return HttpResponse('用户列表')
4.通过url
a、settings
REST_FRAMEWORK = {
'DEFAULT_VERSIONING_CLASS':['rest_framework.versioning.URLPathVersioning'],
'DEFAULT_VERSION': 'v1', # 默认版本
'ALLOWED_VERSIONS': ['v1', 'v2'], # 可支持版本
'VERSION_PARAM': 'version', # 参数
}
b、在视图中通过这样获取
from rest_framework.versioning import URLPathVersioning
class UserView(APIView):
versioning_class = URLPathVersioning
def get(self, request,*args, **kwargs):
print(request.version)
return HttpResponse('用户列表')
c、在url中
urlpatterns = [
url(r'^(?P<version>[v1|v2]+)/users/$', views.UserView.as_view()),
]
二、解析器
1.接收的消息有很多中,rest提供的这两种较为常用:JSONParser
,FormParser
from rest_framework.parsers import JSONParser,FormParser
class ParserView(APIView):
parser_classes = [JSONParser, FormParser]
def get(self, request, *args, **kwargs):
"""
# JSONParser:允许用户发送JSON格式数据 对应请求头:content-type:application/json
# FormParser: 允许用户发送表单格式数据 对应请求头:content-type:application/x-www-form-urlencoded
:param request:
:param args:
:param kwargs:
:return:
"""
print(request.data) # 从这里面拿值
return HttpResponse("Json 格式数据")
- 全局配置
在settings中
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': ['rest_framework.parsers.SONParser','rest_framework.parsers.FormParser']
}
然后在view中直接通过request.data
调用
3.总结:
只需要在全局做好配置就行了
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': ['rest_framework.parsers.SONParser','rest_framework.parsers.FormParser']
}
在获取值的时候用request.data中获取, 如果是上传文件,直接再在单独的视图函数中加入该配置就行了FileUploadParser
。
三、序列化:对请求的数据的验证,对qureyset 进行序列化。
1.数据库的内容进行序列化
# 自己简单实现
import json
from .models import Role
class RolesView(APIView):
def get(self, request, *args, **kwargs):
# 方式一, 自己简单实现
roles = Role.objects.all().values('id', 'title')
roles = list(roles)
ret = json.dumps(roles, ensure_ascii=False)
return HttpResponse(ret)
# query_set 进行序列化
import json
from .models import Role
from rest_framework import serializers
# 通过rest中的序列化来实现。serializers
class RolesSerializer(serializers.Serializer):
title = serializers.CharField() # 这里的字段必须是模型中必须一样
class RolesView(APIView):
def get(self, request, *args, **kwargs):
# 方式二
roles = Role.objects.all().values('id', 'title')
ser = RolesSerializer(instance=roles, many=True)
# ser.data 这是一个字典
ret = json.dumps(ser.data, ensure_ascii=False)
return HttpResponse(ret)
**注意:**上面是对querySet类型进行序列化的用法,如果是object…first 获取的单个对象, 那么RolesSerializer(instance=roles, many=False)
并且就不需要dumps,直接返回ser.data
。
如何对数据库的外键,多对多字段进行序列化,并显示自己想要的字段呢?
from . import models
class UserInfoSerializer(serializers.Serializer):
# 这这里定义哪些字段, 就能序列化哪些字段,并返回。主要是source参数 和自定义函数
user_type = serializers.CharField(source='get_user_type_display') # choice字段显示中文source='get_user_type_display'
username = serializers.CharField()
password = serializers.CharField()
gp = serializers.CharField(source='group.title') # 外键group.title:结果直接显示外键组的title字段
# rls = serializers.CharField(source='roles.all') # 模型中有多对多字段就不能使用这种方式取值显示
rls = serializers.SerializerMethodField() # 自定义显示多对多显示, 允许创建一个自定义的函数,如:get_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 UserInfoView(APIView):
def get(self, request, *args, **kwargs):
# 方式二
user = models.UserInfo.objects.all()
ser = UserInfoSerializer(instance=user, many=True)
ret = json.dumps(ser.data, ensure_ascii=False)
return HttpResponse(ret)
除了上面这种方式序列化以外, rest还提供了另一种方法,搭配使用Meta model。
from . import models
class UserInfoSerializer(serializers.ModelSerializer): # 这里继承ModelSerializer
user_type = serializers.CharField(source='get_user_type_display') # choice字段显示中文source='get_user_type_display'
rls = serializers.SerializerMethodField() # 自定义显示多对多显示, 允许创建一个自定义的函数
class Meta:
model = models.UserInfo
# fields = "__all__" # 这里生成的是模型中对应的字段,但是多对多外键还是比较简单,不是汉字。
fields = ['id', 'username', 'password', 'user_type']
depth = 1 # 这个字段可以帮我们一层一层的取值,对外键和多对多字段使用, 数值是几那么就往后取几层。官方建议0-10之间。即自动序列化连表操作, 这样就可以不用自定义外键字段和多对多字段啦!!!
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 UserInfoView(APIView):
def get(self, request, *args, **kwargs):
user = models.UserInfo.objects.all()
ser = UserInfoSerializer(instance=user, many=True)
ret = json.dumps(ser.data, ensure_ascii=False)
return HttpResponse(ret)
小总结:首先写序列化类,可以继承Serializer,ModelSerializer
这两种,其中ModelSerializer
可以直接使用models中的自定, 如果显示不一样,可以自定制。其他:depth
自动序列化连表操作, 这样就可以不用自定义外键字段和多对多字段。
补充:生成链接,可以基于HyperlinkedModelSerializer
字段来做,这里省略。
2.序列化:请求数据校验
class UserGroupSSerializer(serializers.Serializer):
title = serializers.CharField(error_messages={'required':'标题不能为空'}) #参数校验
class UserGroupView(APIView):
"""序列化之对数据进行校验"""
def post(self,request, *args, **kwargs):
# print(request.data)
ser = UserInfoSerializer(data=request.data)
if ser.is_valid(): # 将传过来的数据进行校验
print(ser.validated_data)
else:
print(ser.errors)
return HttpResponse('提交数据')
钩子函数自定义验证字段。
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from .models import UserModel
class RedisSerializers(serializers.ModelSerializer):
class Meta:
model = UserModel
fields = ("name", "age", "nums", "c_time")
def validate(self, attrs):
"""自定义所以字段验证"""
return attrs
def validate_age(self, data):
"""通过钩子自定义字段验证,validate_[字段名称]"""
if not data:
raise ValidationError(detail="输入错误")
return data
以上方法都是在serializer.is_valid(raise_exception=True)
的时候通过钩子去执行,所以不需要手动执行这两个方法。
3、restframwork渲染器。
# 1. 在settings中先配置好rest_framwork应用
from rest_framework.response import Response # 2 这一步导入Response
class PagerView(APIView):
def get(self, *args, **kwargs):
roles = models.Role.objects.all()
ser = PagerSerializers(instance=roles, many=True)
return Response(ser.data) # 3 这里直接使用,省去我们自己json.dumps()
# 最后访问视图, 就能在页面上看到json格式的数据,并且有样式,
- 分页:
简单使用
a 在settings中配置一页显示的条数
# settings
REST_FRAMEWORK = {
'PAGE_SIZE':10, #配置每页的条数
}
#views
from api.utils.serializsers import PagerSerializers
from rest_framework.response import Response
from rest_framework.pagination import PageNumberPagination
class PagerView(APIView):
def get(self,request, *args, **kwargs):
# 1 获取所有数据
roles = models.Role.objects.all()
# 2 创建分页对象
pg = PageNumberPagination()
# 3 在数据库中获取分页的数据
pager_roles = pg.paginate_queryset(queryset=roles, request=request, view=self)
# 4 对分页的数据进行序列化
ser = PagerSerializers(instance=pager_roles, many=True) # 只序列化获取的分页的数据
print(pager_roles)
return Response(ser.data)
b 自定制分页
# 1.自定制分页,继承PageNumberPagination
class MyPageNumberPagination(PageNumberPagination):
page_size = 5 # 默认每页显示的条数
page_size_query_param = 'size' # 请求带size=10,表示一页显示10条数据,不再使用默认的5条数据
max_page_size = 20 # 这里表示每页最多获取的条数
page_query_param = 'page' # 这里表示页码参数 比如 page=1 表示获取第一页
class PagerView(APIView):
def get(self,request, *args, **kwargs):
# 1 获取所有数据
roles = models.Role.objects.all()
# 2 创建分页对象
pg = MyPageNumberPagination() # 这里使用自己的分页类,实例化
# 3 在数据库中获取分页的数据
pager_roles = pg.paginate_queryset(queryset=roles, request=request, view=self)
# 4 对分页的数据进行序列化
ser = PagerSerializers(instance=pager_roles, many=True) # 只序列化获取的分页的数据
# print(pager_roles)
# pg.get_paginated_response(ser.data) 可以多返回一些参数
# return pg.get_paginated_response(ser.data)
return Response(pg.get_paginated_response(ser.data))
c、 LimitOffsetPagination 分页
原理同上, 只需要定制把定制的重写一下
d、CursorPagination 分页(只有上一页下一页, 加密)
原理同上, 只需要定制把定制的重写一下
5.视图
django-restframwork 视图有:APIView
, 它是最接近django原生的view的。GenericAPIView
它的本质跟APIView
是一样的,只是将部分功能进行打包封装了一下,然后在路由中配置一下对应函数的映射关系即可(个人推荐使用这个视图和APIView)。ModelViewSet
是功能比较齐全的一个view,他封装的查询集 序列化,以及分页,并且继承了增删改查的自个mixin, 如果不需要定制化内容, 完全可以使用ModelViewSet
。
# views
class BodyView(GenericAPIView):
queryset = models.Role.objects.all()
serializer_class = PagerSerializers
pagenation_class = PageNumberPagination
def get(self,request, *args, **kwargs):
roles = self.get_queryset() #models.Role.objects.all()
pager_roles = self.paginate_queryset(roles) # 分页
ser = self.get_serializer(instance=pager_roles, many=True)
return Response(ser.data)
# urls
urlpatterns = [
url(r'^(?P<version>[v1|v2]+)/user/$', views.BodyView.as_view({'get':'get'})),
]
6. 路由,只需在urls中导入routers, 然后注册即可。
7.渲染器