请求参考:Django Restful Framework【第四篇】版本、解析器、序列化和请求数据验证
一、版本
程序也来越大时,可能通过版本不同做不同的处理
没用rest_framework之前,我们可以通过以下这样的方式去获取。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
class UserView(APIView): def get( self ,request, * args, * * kwargs): version = request.query_params.get( 'version' ) print (version) if version = = 'v1' : #如果版本是v1 ret = { 'code' : 111 , 'msg' : '版本一的内容' } elif version = = 'v2' : # 如果是v2 ret = { 'code' : 112 , 'msg' : '版本二的内容' } else : ret = { 'code' : 0 , 'msg' : '不支持其他版本' } return Response(ret) |
现在我们来用rest_framework实现一下,有两种方式
1、基于url的方式
#基于url传参的形式 versioning_class = QueryParameterVersioning #http://127.0.0.1:8080/api/users/?version=v2 #基于url的形式 versioning_class = URLPathVersioning #http://127.0.0.1:8080/api/v1/users/
具体步骤
1
2
3
4
5
|
REST_FRAMEWORK = { 'DEFAULT_VERSION' : 'v1' , #默认的版本 'ALLOWED_VERSIONS' : [ 'v1' , 'v2' ], #允许的版本 'VERSION_PARAM' : 'version' , } |
1
2
3
4
5
6
7
8
|
from django.conf.urls import url,include from django.contrib import admin urlpatterns = [ url(r '^admin/' , admin.site.urls), url(r '^api/(?P<version>[v1|v2]+)/' , include( 'api.urls' ), name = 'users-list' ), ] |
1
2
3
4
5
6
|
from api import views urlpatterns = [ # url(r'^users/', views.UserView.as_view()), url(r '^users/' , views.UserView1.as_view()), ] |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
class UserView1(APIView): #基于url传参的形式 # versioning_class = QueryParameterVersioning #http://127.0.0.1:8080/api/users/?version=v2 #基于url的形式 #http://127.0.0.1:8080/api/v1/users/ versioning_class = URLPathVersioning def get( self ,request, * args, * * kwargs): # self.dispatch print (request.version) #打印的是版本 print (request.versioning_scheme) #打印的是对象 if request.version = = 'v2' : return Response( '我是版本二' ) elif request.version = = 'v1' : return Response( '我是版本一' ) else : return Response( '去去去' ) |
注:在配置的时候
REST_FRAMEWORK = { 'VERSION_PARAM':'version', 'DEFAULT_VERSION':'v1', 'ALLOWED_VERSIONS':['v1','v2'], # 'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.HostNameVersioning"
#如果加上这个配置就不用versioning_class = QueryParameterVersioning这样在指定了,
'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning" }
附加:restful提供的反向生成
#http://127.0.0.1:8080/api/v1/users/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#urls.py #分发路由 urlpatterns = [ url(r '^admin/' , admin.site.urls), url(r '^api/(?P<version>[v1|v2]+)/' , include( 'api.urls' )), ] #api.urls.py urlpatterns = [ url(r '^users/' , views.UserView1.as_view(), name = 'users-list' ), ] #views.py 导入类 from rest_framework.reverse import reverse url = request.versioning_scheme.reverse(viewname = 'users-list' ,request = request) print (url) |
我们自己用django实现的,当前版本不一样的时候可以用这种方式
from django.urls import reverse url = reverse(viewname='users-list',kwargs={'version':'v2'}) #指定的是v2就是v2,当你路径中输入v1的时候还是v2的路径 print(url) #/api/v2/users/
2、基于子域名传参
如果遇到这样的错误
这是由于没有允许,解决办法,在settings里面配置一下
ALLOWED_HOSTS = ['*']
二、解析器:reqest.data取值的时候才执行
对请求的数据进行解析:是针对请求体进行解析的。表示服务器可以解析的数据格式的种类
django中的发送请求
#如果是这样的格式发送的数据,在POST里面有值 Content-Type: application/url-encoding..... request.body request.POST #如果是发送的json的格式,在POST里面是没有值的,在body里面有值,可通过decode,然后loads取值 Content-Type: application/json..... request.body request.POST
为了这种情况下每次都要decode,loads,显得麻烦,所以才有的解析器。弥补了django的缺点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
#具体讲解 客户端: Content - Type : application / json '{"name":"alex","age":123}' 服务端接收: 读取客户端发送的Content - Type 的值 application / json parser_classes = [JSONParser,FormParser] #表示服务器可以解析的数据格式的种类 media_type_list = [ 'application/json' , 'application/x-www-form-urlencoded' ] 如果客户端的Content - Type 的值和 application / json 匹配:JSONParser处理数据 如果客户端的Content - Type 的值和 application / x - www - form - urlencoded 匹配:FormParser处理数据 配置: 单视图: class UsersView(APIView): parser_classes = [JSONParser,] 全局配置: REST_FRAMEWORK = { 'VERSION_PARAM' : 'version' , 'DEFAULT_VERSION' : 'v1' , 'ALLOWED_VERSIONS' :[ 'v1' , 'v2' ], # 'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.HostNameVersioning" 'DEFAULT_VERSIONING_CLASS' : "rest_framework.versioning.URLPathVersioning" , 'DEFAULT_PARSER_CLASSES' :[ 'rest_framework.parsers.JSONParser' , 'rest_framework.parsers.FormParser' , ] } class UserView(APIView): def get( self ,request, * args, * * kwargs): return Response( 'ok' ) def post( self ,request, * args, * * kwargs): print (request.data) #以后取值就在这里面去取值 return Response( '...' ) |
传上传文件
1
2
3
4
5
6
|
from django.conf.urls import url, include from web.views import TestView urlpatterns = [ url(r 'test/(?P<filename>[^/]+)' , TestView.as_view(), name = 'test' ), ] |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.request import Request from rest_framework.parsers import FileUploadParser class TestView(APIView): parser_classes = [FileUploadParser, ] def post( self , request, filename, * args, * * kwargs): print (filename) print (request.content_type) # 获取请求的值,并使用对应的JSONParser进行处理 print (request.data) # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值 print (request.POST) print (request.FILES) return Response( 'POST请求,响应内容' ) def put( self , request, * args, * * kwargs): return Response( 'PUT请求,响应内容' ) |
upload.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<!DOCTYPE html> <html lang = "en" > <head> <meta charset = "UTF-8" > <title>Title< / title> < / head> <body> <form action = "http://127.0.0.1:8000/test/f1.numbers" method = "post" enctype = "multipart/form-data" > < input type = "text" name = "user" / > < input type = "file" name = "img" > < input type = "submit" value = "提交" > < / form> < / body> < / html> |
全局使用
1
2
3
4
5
6
7
8
|
REST_FRAMEWORK = { 'DEFAULT_PARSER_CLASSES' :[ 'rest_framework.parsers.JSONParser' 'rest_framework.parsers.FormParser' 'rest_framework.parsers.MultiPartParser' ] } |
三、序列化
序列化用于对用户请求数据进行验证和数据进行序列化(为了解决queryset序列化问题)。
那什么是序列化呢?序列化就是把对象转换成字符串,反序列化就是把字符串转换成对象
models.py
from django.db import models # Create your models here. class Group(models.Model): title = models.CharField(max_length=32) mu = models.ForeignKey(to='Menu',default=1) class UserInfo(models.Model): name = models.CharField(max_length=32) pwd = models.CharField(max_length=32) group = models.ForeignKey(to="Group") roles = models.ManyToManyField(to="Role") class Menu(models.Model): name = models.CharField(max_length=21) class Role(models.Model): name = models.CharField(max_length=32)
1、基本操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
from django.shortcuts import render,HttpResponse from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.versioning import BaseVersioning from rest_framework.versioning import QueryParameterVersioning #获取version的值 from rest_framework.versioning import URLPathVersioning #支持版本 from rest_framework.versioning import HostNameVersioning from rest_framework.parsers import JSONParser #解析器 from rest_framework import serializers from app03 import models class UsersSerializer(serializers.Serializer): name = serializers.CharField() #字段名字 pwd = serializers.CharField() class UserView(APIView): def get( self ,request, * args, * * kwargs): # 方式一实现 # user_list = models.UserInfo.objects.values('name','pwd','group__mu','group__title') # print(type(user_list)) # return Response(user_list) # 方式二之多对象 # user_list = models.UserInfo.objects.all() #直接这样查会报错,借助他提供的系列化 # ser = UsersSerializer(instance=user_list,many=True) #可允许多个 # # print(type(ser)) #<class 'rest_framework.serializers.ListSerializer'> # print(ser.data) #返回的是一个有序字典 #方式三之单对象 user = models.UserInfo.objects. all ().first() ser = UsersSerializer(instance = user,many = False ) return Response(ser.data) |
2、跨表
x1 = serializers.CharField(source='group.mu.name')
如果你想跨表拿你任何需要的数据,都可以用上面的这种操作,内部做判断,如果可用内部就加括号调用了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import serializers from app03 import models class UsersSerializer(serializers.Serializer): name = serializers.CharField() #字段名字 pwd = serializers.CharField() # group = serializers.CharField() #会显示对象 # group_id = serializers.CharField() #会显示id x1 = serializers.CharField(source = 'group.mu.name' ) roles = serializers.CharField(source = 'roles.all' ) #多对多关系的这样查出的是queryset对象 class UserView2(APIView): '''跨表操作''' def get( self ,request, * args, * * kwargs): user = models.UserInfo.objects. all () ser = UsersSerializer(instance = user,many = True ) return Response(ser.data) |
3、复杂序列化
解决方案一:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
class MyCharField(serializers.CharField): def to_representation( self , value): ##打印的是所有的数据 data_list = [] for row in value: data_list.append(row.name) return data_list class UsersSerializer(serializers.Serializer): name = serializers.CharField() # obj.name pwd = serializers.CharField() # obj.pwd group_id = serializers.CharField() # obj.group_id xxxx = serializers.CharField(source = "group.title" ) # obj.group.title x1 = serializers.CharField(source = "group.mu.name" ) # obj.mu.name # x2 = serializers.CharField(source="roles.all") # 多对多关系的这样查出的是queryset对象 x2 = MyCharField(source = "roles.all" ) # obj.mu.name |
解决方案二:
1
2
3
4
5
6
7
8
9
10
11
12
|
class MyCharField(serializers.CharField): def to_representation( self , value): return { 'id' :value.pk, 'name' :value.name} class UsersSerializer(serializers.Serializer): name = serializers.CharField() # obj.name pwd = serializers.CharField() # obj.pwd group_id = serializers.CharField() # obj.group_id xxxx = serializers.CharField(source = "group.title" ) # obj.group.title x1 = serializers.CharField(source = "group.mu.name" ) # obj.mu.name # x2 = serializers.CharField(source="roles.all") # obj.mu.name x2 = serializers.ListField(child = MyCharField(),source = "roles.all" ) # obj.mu.name |
解决方案三(推荐使用)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
class UsersSerializer(serializers.Serializer): name = serializers.CharField() # obj.name pwd = serializers.CharField() # obj.pwd group_id = serializers.CharField() # obj.group_id xxxx = serializers.CharField(source = "group.title" ) # obj.group.title x1 = serializers.CharField(source = "group.mu.name" ) # obj.mu.name # x2 = serializers.CharField(source="roles.all") # obj.mu.name # x2 = serializers.ListField(child=MyCharField(),source="roles.all") # obj.mu.name x2 = serializers.SerializerMethodField() def get_x2( self ,obj): #get_字段名 print (obj) ##UserInfo object obj.roles. all () role_list = obj.roles. filter (id__gt = 1 ) data_list = [] for row in role_list: data_list.append({ 'pk' :row.pk, 'name' :row.name}) return data_list |
4、基于Model
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
class UsersSerializer(serializers.ModelSerializer): x1 = serializers.CharField(source = 'name' ) group = serializers.HyperlinkedIdentityField(view_name = 'detail' ) class Meta: model = models.UserInfo # fields = "__all__" fields = [ 'name' , 'pwd' , 'group' , 'x1' ] #自定义字段的时候注意要指定source,scource里面的数据必须是数据库有的数据 depth = 1 #表示深度 class UsersView(APIView): def get( self ,request, * args, * * kwargs): self .dispatch # 方式一: # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title") # return Response(user_list) # 方式二之多对象 user_list = models.UserInfo.objects. all () # [obj1,obj2,obj3] ser = UsersSerializer(instance = user_list,many = True ) return Response(ser.data) Views.py |
5、生成URL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
class UsersSerializer(serializers.ModelSerializer): # group = serializers.HyperlinkedIdentityField(view_name = 'detail' ) class Meta: model = models.UserInfo fields = "__all__" fields = [ 'name' , 'pwd' , 'group' ] depth = 1 class UsersView(APIView): def get( self ,request, * args, * * kwargs): self .dispatch # 方式一: # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title") # return Response(user_list) # 方式二之多对象 user_list = models.UserInfo.objects. all () # [obj1,obj2,obj3] ser = UsersSerializer(instance = user_list,many = True ,context = { 'request' :request}) return Response(ser.data) |
from django.conf.urls import url,include from django.contrib import admin from app03 import views urlpatterns = [ url(r'^users4/', views.UserView4.as_view(), name='xxx'), #吧users4的group的值反向生成users5的url url(r'^users5/(?P<pk>.*)', views.UserView5.as_view(), name='detail'), #必须叫pk # url(r'^users4/(?P<pk>.*)', views.UserView4.as_view(), name='detail'), ]
6、全局生成URL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
class UsersSerializer(serializers.HyperlinkedModelSerializer): #继承他自动生成 class Meta: model = models.UserInfo fields = "__all__" # fields = ['id','name','pwd'] class UsersView(APIView): def get( self ,request, * args, * * kwargs): self .dispatch # 方式一: # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title") # return Response(user_list) # 方式二之多对象 user_list = models.UserInfo.objects. all () # [obj1,obj2,obj3] ser = UsersSerializer(instance = user_list,many = True ,context = { 'request' :request}) return Response(ser.data) |

四、请求数据验证:
a、自己手写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
class PasswordValidator( object ): def __init__( self , base): self .base = base def __call__( self , value): if value ! = 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 UsersSerializer(serializers.Serializer): name = serializers.CharField(min_length = 6 ) pwd = serializers.CharField(error_messages = { 'required' : '密码不能为空' }, validators = [PasswordValidator( '666' )]) |
b、基于model
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
class PasswordValidator( object ): def __init__( self , base): self .base = base def __call__( self , value): if value ! = 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 UsersSerializer(serializers.Serializer): name = serializers.CharField(min_length = 6 ) pwd = serializers.CharField(error_messages = { 'required' : '密码不能为空' }, validators = [PasswordValidator( '666' )]) |
使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
class UsersView(APIView): def get( self ,request, * args, * * kwargs): self .dispatch # 方式一: # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title") # return Response(user_list) # 方式二之多对象 user_list = models.UserInfo.objects. all () # [obj1,obj2,obj3] ser = UsersSerializer(instance = user_list,many = True ,context = { 'request' :request}) return Response(ser.data) def post( self ,request, * args, * * kwargs): ser = UsersSerializer(data = request.data) if ser.is_valid(): print (ser.validated_data) else : print (ser.errors) return Response( '...' ) |
钩子函数
def validate_字段(self,validated_value): raise ValidationError(detail='xxxxxx') return validated_value
posted on 2018-05-16 13:06 myworldworld 阅读(128) 评论(0) 收藏 举报