一、版本
程序也来越大时,可能通过版本不同做不同的处理
没用rest_framework之前,我们可以通过以下这样的方式去获取。

1 class UserView(APIView): 2 def get(self,request,*args,**kwargs): 3 version = request.query_params.get('version') 4 print(version) 5 if version=='v1': 6 #如果版本是v1 7 ret = { 8 'code':111, 9 'msg':'版本一的内容' 10 } 11 12 elif version=='v2': 13 # 如果是v2 14 ret = { 15 'code': 112, 16 'msg': '版本二的内容' 17 } 18 else: 19 ret = { 20 'code': 0, 21 'msg': '不支持其他版本' 22 } 23 return Response(ret)
现在我们来用rest_framework实现一下
a. 基于url的get传参方式
如:/users?version=v1

REST_FRAMEWORK = { 'DEFAULT_VERSION': 'v1', # 默认版本 'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本 'VERSION_PARAM': 'version' # URL中获取值的key }

from django.conf.urls import url, include from web.views import TestView urlpatterns = [ url(r'^test/', TestView.as_view(),name='test'), ]

#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.versioning import QueryParameterVersioning class TestView(APIView): versioning_class = QueryParameterVersioning def get(self, request, *args, **kwargs): # 获取版本 print(request.version) # 获取版本管理的类 print(request.versioning_scheme) # 反向生成URL reverse_url = request.versioning_scheme.reverse('test', request=request) print(reverse_url) return Response('GET请求,响应内容') def post(self, request, *args, **kwargs): return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容')
b. 基于url的正则方式
如:/v1/users/

REST_FRAMEWORK = { 'DEFAULT_VERSION': 'v1', # 默认版本 'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本 'VERSION_PARAM': 'version' # URL中获取值的key }

from django.conf.urls import url, include from web.views import TestView urlpatterns = [ url(r'^(?P<version>[v1|v2]+)/test/', TestView.as_view(), name='test'), ]

#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.versioning import URLPathVersioning class TestView(APIView): versioning_class = URLPathVersioning def get(self, request, *args, **kwargs): # 获取版本 print(request.version) # 获取版本管理的类 print(request.versioning_scheme) # 反向生成URL reverse_url = request.versioning_scheme.reverse('test', request=request) print(reverse_url) return Response('GET请求,响应内容') def post(self, request, *args, **kwargs): return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容')
c. 基于 accept 请求头方式
如:Accept: application/json; version=1.0

REST_FRAMEWORK = { 'DEFAULT_VERSION': 'v1', # 默认版本 'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本 'VERSION_PARAM': 'version' # URL中获取值的key }

from django.conf.urls import url, include from web.views import TestView urlpatterns = [ url(r'^test/', TestView.as_view(), name='test'), ]

#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.versioning import AcceptHeaderVersioning class TestView(APIView): versioning_class = AcceptHeaderVersioning def get(self, request, *args, **kwargs): # 获取版本 HTTP_ACCEPT头 print(request.version) # 获取版本管理的类 print(request.versioning_scheme) # 反向生成URL reverse_url = request.versioning_scheme.reverse('test', request=request) print(reverse_url) return Response('GET请求,响应内容') def post(self, request, *args, **kwargs): return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容')
d. 基于主机名方法
如:v1.example.com

ALLOWED_HOSTS = ['*'] REST_FRAMEWORK = { 'DEFAULT_VERSION': 'v1', # 默认版本 'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本 'VERSION_PARAM': 'version' # URL中获取值的key }

from django.conf.urls import url, include from web.views import TestView urlpatterns = [ url(r'^test/', TestView.as_view(), name='test'), ]

#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.versioning import HostNameVersioning class TestView(APIView): versioning_class = HostNameVersioning def get(self, request, *args, **kwargs): # 获取版本 print(request.version) # 获取版本管理的类 print(request.versioning_scheme) # 反向生成URL reverse_url = request.versioning_scheme.reverse('test', request=request) print(reverse_url) return Response('GET请求,响应内容') def post(self, request, *args, **kwargs): return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容')

#分发url urlpatterns = [ #url(r'^admin/', admin.site.urls), url(r'^api/', include('api.urls')), ] urlpatterns = [ url(r'^users/', views.UsersView.as_view(),name='u'), ] class UsersView(APIView): def get(self,request,*args,**kwargs): self.dispatch print(request.version) # QueryParameterVersioning().detemiin_version() print(request.versioning_scheme) # QueryParameterVersioning() REST_FRAMEWORK = { 'VERSION_PARAM':'version', 'DEFAULT_VERSION':'v1', 'ALLOWED_VERSIONS':['v1','v2'], 'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.HostNameVersioning" } # C:WindowsSystem32driversetc # vim /etc/hosts 127.0.0.1 v1.luffy.com 127.0.0.1 v2.luffy.com #配置ALLOWED_HOSTS = ['*']
如果遇到这样的错误
这是由于没有允许,解决办法,在settings里面配置一下
ALLOWED_HOSTS = ['*']
e. 基于django路由系统的namespace
如:example.com/v1/users/

REST_FRAMEWORK = { 'DEFAULT_VERSION': 'v1', # 默认版本 'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本 'VERSION_PARAM': 'version' # URL中获取值的key }

from django.conf.urls import url, include from web.views import TestView urlpatterns = [ url(r'^v1/', ([ url(r'test/', TestView.as_view(), name='test'), ], None, 'v1')), url(r'^v2/', ([ url(r'test/', TestView.as_view(), name='test'), ], None, 'v2')), ]

#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.versioning import NamespaceVersioning class TestView(APIView): versioning_class = NamespaceVersioning def get(self, request, *args, **kwargs): # 获取版本 print(request.version) # 获取版本管理的类 print(request.versioning_scheme) # 反向生成URL reverse_url = request.versioning_scheme.reverse('test', request=request) print(reverse_url) return Response('GET请求,响应内容') def post(self, request, *args, **kwargs): return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容')
#http://127.0.0.1:8080/api/v1/users/

#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/
f. 全局使用

REST_FRAMEWORK = { 'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning", 'DEFAULT_VERSION': 'v1', 'ALLOWED_VERSIONS': ['v1', 'v2'], 'VERSION_PARAM': 'version' }
注:在配置的时候
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" }
二、解析器(parser) :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 Content-Type: application/json 3 '{"name":"alex","age":123}' 4 5 服务端接收: 6 读取客户端发送的Content-Type的值 application/json 7 8 parser_classes = [JSONParser,FormParser] #表示服务器可以解析的数据格式的种类 9 media_type_list = ['application/json','application/x-www-form-urlencoded'] 10 11 如果客户端的Content-Type的值和 application/json 匹配:JSONParser处理数据 12 如果客户端的Content-Type的值和 application/x-www-form-urlencoded 匹配:FormParser处理数据 13 14 15 配置: 16 单视图: 17 class UsersView(APIView): 18 parser_classes = [JSONParser,] 19 20 全局配置: 21 REST_FRAMEWORK = { 22 'VERSION_PARAM':'version', 23 'DEFAULT_VERSION':'v1', 24 'ALLOWED_VERSIONS':['v1','v2'], 25 # 'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.HostNameVersioning" 26 'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning", 27 'DEFAULT_PARSER_CLASSES':[ 28 'rest_framework.parsers.JSONParser', 29 'rest_framework.parsers.FormParser', 30 ] 31 } 32 33 class UserView(APIView): 34 def get(self,request,*args,**kwargs): 35 return Response('ok') 36 def post(self,request,*args,**kwargs): 37 print(request.data) #以后取值就在这里面去取值 38 return Response('...')
根据请求头 content-type 选择对应的解析器就请求体内容进行处理。
a. 仅处理请求头content-type为application/json的请求体

from django.conf.urls import url, include from web.views.s5_parser import TestView urlpatterns = [ url(r'test/', TestView.as_view(), name='test'), ]

#!/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 JSONParser class TestView(APIView): parser_classes = [JSONParser, ] def post(self, request, *args, **kwargs): 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请求,响应内容')
b. 仅处理请求头content-type为application/x-www-form-urlencoded 的请求体

from django.conf.urls import url, include from web.views import TestView urlpatterns = [ url(r'test/', TestView.as_view(), name='test'), ]

#!/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 FormParser class TestView(APIView): parser_classes = [FormParser, ] def post(self, request, *args, **kwargs): 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请求,响应内容')
c. 仅处理请求头content-type为multipart/form-data的请求体

from django.conf.urls import url, include from web.views import TestView urlpatterns = [ url(r'test/', TestView.as_view(), name='test'), ]

#!/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 MultiPartParser class TestView(APIView): parser_classes = [MultiPartParser, ] def post(self, request, *args, **kwargs): 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请求,响应内容')

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="http://127.0.0.1:8000/test/" method="post" enctype="multipart/form-data"> <input type="text" name="user" /> <input type="file" name="img"> <input type="submit" value="提交"> </form> </body> </html>
d. 仅上传文件

1 from django.conf.urls import url, include 2 from web.views import TestView 3 4 urlpatterns = [ 5 url(r'test/(?P<filename>[^/]+)', TestView.as_view(), name='test'), 6 ]

1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from rest_framework.views import APIView 4 from rest_framework.response import Response 5 from rest_framework.request import Request 6 from rest_framework.parsers import FileUploadParser 7 8 9 class TestView(APIView): 10 parser_classes = [FileUploadParser, ] 11 12 def post(self, request, filename, *args, **kwargs): 13 print(filename) 14 print(request.content_type) 15 16 # 获取请求的值,并使用对应的JSONParser进行处理 17 print(request.data) 18 # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值 19 print(request.POST) 20 print(request.FILES) 21 return Response('POST请求,响应内容') 22 23 def put(self, request, *args, **kwargs): 24 return Response('PUT请求,响应内容')

1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body> 8 <form action="http://127.0.0.1:8000/test/f1.numbers" method="post" enctype="multipart/form-data"> 9 <input type="text" name="user" /> 10 <input type="file" name="img"> 11 12 <input type="submit" value="提交"> 13 14 </form> 15 </body> 16 </html>
e. 同时多个Parser
当同时使用多个parser时,rest framework会根据请求头content-type自动进行比对,并使用对应parser

from django.conf.urls import url, include from web.views import TestView urlpatterns = [ url(r'test/', TestView.as_view(), name='test'), ]

#!/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 JSONParser, FormParser, MultiPartParser class TestView(APIView): parser_classes = [JSONParser, FormParser, MultiPartParser, ] def post(self, request, *args, **kwargs): 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请求,响应内容')
f.全局使用

REST_FRAMEWORK = { 'DEFAULT_PARSER_CLASSES':[ 'rest_framework.parsers.JSONParser' 'rest_framework.parsers.FormParser' 'rest_framework.parsers.MultiPartParser' ] }

from django.conf.urls import url, include from web.views import TestView urlpatterns = [ url(r'test/', TestView.as_view(), name='test'), ]

#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response class TestView(APIView): def post(self, request, *args, **kwargs): 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请求,响应内容')
request.data取POST的值
注意:个别特殊的值可以通过Django的request对象 request._request 来进行获取
获取get的数据,可以通过request._request.GET或者request.query_params或request.GET
因为

def dispatch(self, request, *args, **kwargs): """ `.dispatch()` is pretty much the same as Django's regular dispatch, but with extra hooks for startup, finalize, and exception handling. """ self.args = args self.kwargs = kwargs # 第一步:对request进行加工(添加数据) request = self.initialize_request(request, *args, **kwargs) self.request = request

def __init__(self, request, parsers=None, authenticators=None, negotiator=None, parser_context=None): assert isinstance(request, HttpRequest), ( 'The `request` argument must be an instance of ' '`django.http.HttpRequest`, not `{}.{}`.' .format(request.__class__.__module__, request.__class__.__name__) ) self._request = request #将django中的request对象封装到了_request中

def __getattr__(self, attr): """ If an attribute does not exist on this instance, then we also attempt to proxy it to the underlying HttpRequest object. """ try: return getattr(self._request, attr) #当在新的request中找不到时,就去原来的request中找 except AttributeError: return self.__getattribute__(attr)
三、序列化
序列化用于对用户请求数据进行验证和数据进行序列化(为了解决queryset序列化问题)。
那什么是序列化呢?序列化就是把对象转换成字符串,反序列化就是把字符串转换成对象
a. 自定义字段

from django.conf.urls import url, include from web.views.s6_serializers import TestView urlpatterns = [ url(r'test/', TestView.as_view(), name='test'), ]

#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import serializers from .. import models class PasswordValidator(object): def __init__(self, base): self.base = base def __call__(self, value): if value != self.base: message = 'This field must be %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 UserSerializer(serializers.Serializer): ut_title = serializers.CharField(source='ut.title') user = serializers.CharField(min_length=6) pwd = serializers.CharField(error_messages={'required': '密码不能为空'}, validators=[PasswordValidator('666')]) class TestView(APIView): def get(self, request, *args, **kwargs): # 序列化,将数据库查询字段序列化为字典 data_list = models.UserInfo.objects.all() ser = UserSerializer(instance=data_list, many=True) # 或 # obj = models.UserInfo.objects.all().first() # ser = UserSerializer(instance=obj, many=False) return Response(ser.data) def post(self, request, *args, **kwargs): # 验证,对请求发来的数据进行验证 ser = UserSerializer(data=request.data) if ser.is_valid(): print(ser.validated_data) else: print(ser.errors) return Response('POST请求,响应内容')
b. 基于Model自动生成字段

from django.conf.urls import url, include from web.views.s6_serializers import TestView urlpatterns = [ url(r'test/', TestView.as_view(), name='test'), ]

#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import serializers from .. import models class PasswordValidator(object): def __init__(self, base): self.base = str(base) def __call__(self, value): if value != self.base: message = 'This field must be %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 ModelUserSerializer(serializers.ModelSerializer): user = serializers.CharField(max_length=32) class Meta: model = models.UserInfo fields = "__all__" # fields = ['user', 'pwd', 'ut'] depth = 2 extra_kwargs = {'user': {'min_length': 6}, 'pwd': {'validators': [PasswordValidator(666), ]}} # read_only_fields = ['user'] class TestView(APIView): def get(self, request, *args, **kwargs): # 序列化,将数据库查询字段序列化为字典 data_list = models.UserInfo.objects.all() ser = ModelUserSerializer(instance=data_list, many=True) # 或 # obj = models.UserInfo.objects.all().first() # ser = UserSerializer(instance=obj, many=False) return Response(ser.data) def post(self, request, *args, **kwargs): # 验证,对请求发来的数据进行验证 print(request.data) ser = ModelUserSerializer(data=request.data) if ser.is_valid(): print(ser.validated_data) else: print(ser.errors) return Response('POST请求,响应内容')
c. 生成URL

from django.conf.urls import url, include from web.views.s6_serializers import TestView urlpatterns = [ url(r'test/', TestView.as_view(), name='test'), url(r'detail/(?P<pk>d+)/', TestView.as_view(), name='detail'), ]

#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import serializers from .. import models class PasswordValidator(object): def __init__(self, base): self.base = str(base) def __call__(self, value): if value != self.base: message = 'This field must be %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 ModelUserSerializer(serializers.ModelSerializer): ut = serializers.HyperlinkedIdentityField(view_name='detail') class Meta: model = models.UserInfo fields = "__all__" extra_kwargs = { 'user': {'min_length': 6}, 'pwd': {'validators': [PasswordValidator(666),]}, } class TestView(APIView): def get(self, request, *args, **kwargs): # 序列化,将数据库查询字段序列化为字典 data_list = models.UserInfo.objects.all() ser = ModelUserSerializer(instance=data_list, many=True, context={'request': request}) # 或 # obj = models.UserInfo.objects.all().first() # ser = UserSerializer(instance=obj, many=False) return Response(ser.data) def post(self, request, *args, **kwargs): # 验证,对请求发来的数据进行验证 print(request.data) ser = ModelUserSerializer(data=request.data) if ser.is_valid(): print(ser.validated_data) else: print(ser.errors) return Response('POST请求,响应内容')
d. 自动生成URL

from django.conf.urls import url, include from web.views.s6_serializers import TestView urlpatterns = [ url(r'test/', TestView.as_view(), name='test'), url(r'detail/(?P<pk>d+)/', TestView.as_view(), name='xxxx'), ]

#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import serializers from .. import models class PasswordValidator(object): def __init__(self, base): self.base = str(base) def __call__(self, value): if value != self.base: message = 'This field must be %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 ModelUserSerializer(serializers.HyperlinkedModelSerializer): ll = serializers.HyperlinkedIdentityField(view_name='xxxx') tt = serializers.CharField(required=False) class Meta: model = models.UserInfo fields = "__all__" list_serializer_class = serializers.ListSerializer extra_kwargs = { 'user': {'min_length': 6}, 'pwd': {'validators': [PasswordValidator(666), ]}, 'url': {'view_name': 'xxxx'}, 'ut': {'view_name': 'xxxx'}, } class TestView(APIView): def get(self, request, *args, **kwargs): # # 序列化,将数据库查询字段序列化为字典 data_list = models.UserInfo.objects.all() ser = ModelUserSerializer(instance=data_list, many=True, context={'request': request}) # # 如果Many=True # # 或 # # obj = models.UserInfo.objects.all().first() # # ser = UserSerializer(instance=obj, many=False) return Response(ser.data) def post(self, request, *args, **kwargs): # 验证,对请求发来的数据进行验证 print(request.data) ser = ModelUserSerializer(data=request.data) if ser.is_valid(): print(ser.validated_data) else: print(ser.errors) return Response('POST请求,响应内容')
1、基本操作

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 from django.shortcuts import render,HttpResponse 2 from rest_framework.views import APIView 3 from rest_framework.response import Response 4 from rest_framework.versioning import BaseVersioning 5 from rest_framework.versioning import QueryParameterVersioning #获取version的值 6 from rest_framework.versioning import URLPathVersioning #支持版本 7 from rest_framework.versioning import HostNameVersioning 8 from rest_framework.parsers import JSONParser #解析器 9 from rest_framework import serializers 10 from app03 import models 11 class UsersSerializer(serializers.Serializer): 12 name = serializers.CharField() #字段名字 13 pwd = serializers.CharField() 14 15 class UserView(APIView): 16 def get(self,request,*args,**kwargs): 17 # 方式一实现 18 # user_list = models.UserInfo.objects.values('name','pwd','group__mu','group__title') 19 # print(type(user_list)) 20 # return Response(user_list) 21 22 # 方式二之多对象 23 # user_list = models.UserInfo.objects.all() #直接这样查会报错,借助他提供的系列化 24 # ser = UsersSerializer(instance=user_list,many=True) #可允许多个 25 # # print(type(ser)) #<class 'rest_framework.serializers.ListSerializer'> 26 # print(ser.data) #返回的是一个有序字典 27 28 #方式三之单对象 29 user = models.UserInfo.objects.all().first() 30 ser = UsersSerializer(instance=user,many=False) 31 32 return Response(ser.data)
2、跨表
x1 = serializers.CharField(source='group.mu.name')
如果你想跨表拿你任何需要的数据,都可以用上面的这种操作,内部做判断,如果可用内部就加括号调用了

1 from rest_framework.views import APIView 2 from rest_framework.response import Response 3 from rest_framework import serializers 4 from app03 import models 5 class UsersSerializer(serializers.Serializer): 6 name = serializers.CharField() #字段名字 7 pwd = serializers.CharField() 8 # group = serializers.CharField() #会显示对象 9 # group_id = serializers.CharField() #会显示id 10 x1 = serializers.CharField(source='group.mu.name') 11 roles = serializers.CharField(source='roles.all') #多对多关系的这样查出的是queryset对象 12 13 class UserView2(APIView): 14 '''跨表操作''' 15 def get(self,request,*args,**kwargs): 16 17 user = models.UserInfo.objects.all() 18 ser = UsersSerializer(instance=user,many=True) 19 20 return Response(ser.data)
3、复杂序列化
自定义类和方法
解决方案一:

1 class MyCharField(serializers.CharField): 2 3 def to_representation(self, value): ##打印的是所有的数据 4 data_list = [] 5 for row in value: 6 data_list.append(row.name) 7 return data_list 8 9 class UsersSerializer(serializers.Serializer): 10 name = serializers.CharField() # obj.name 11 pwd = serializers.CharField() # obj.pwd 12 group_id = serializers.CharField() # obj.group_id 13 xxxx = serializers.CharField(source="group.title") # obj.group.title 14 x1 = serializers.CharField(source="group.mu.name") # obj.mu.name 15 # x2 = serializers.CharField(source="roles.all") # 多对多关系的这样查出的是queryset对象 16 x2 = MyCharField(source="roles.all") # obj.mu.name
解决方案二:

1 class MyCharField(serializers.CharField): 2 def to_representation(self, value): 3 return {'id':value.pk, 'name':value.name} 4 5 class UsersSerializer(serializers.Serializer): 6 name = serializers.CharField() # obj.name 7 pwd = serializers.CharField() # obj.pwd 8 group_id = serializers.CharField() # obj.group_id 9 xxxx = serializers.CharField(source="group.title") # obj.group.title 10 x1 = serializers.CharField(source="group.mu.name") # obj.mu.name 11 # x2 = serializers.CharField(source="roles.all") # obj.mu.name 12 x2 = serializers.ListField(child=MyCharField(),source="roles.all") # obj.mu.name
解决方案三(推荐使用)

1 class UsersSerializer(serializers.Serializer): 2 name = serializers.CharField() # obj.name 3 pwd = serializers.CharField() # obj.pwd 4 group_id = serializers.CharField() # obj.group_id 5 xxxx = serializers.CharField(source="group.title") # obj.group.title 6 x1 = serializers.CharField(source="group.mu.name") # obj.mu.name 7 # x2 = serializers.CharField(source="roles.all") # obj.mu.name 8 # x2 = serializers.ListField(child=MyCharField(),source="roles.all") # obj.mu.name 9 x2 = serializers.SerializerMethodField() 10 11 def get_x2(self,obj): #get_字段名 12 print(obj) ##UserInfo object 13 obj.roles.all() 14 role_list = obj.roles.filter(id__gt=1) 15 data_list = [] 16 for row in role_list: 17 data_list.append({'pk':row.pk,'name':row.name}) 18 return data_list 19
4、基于Model

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)
当我们想定义一个model中没有的字段时,可以采用以下方式
class NewhomeSerializer(serializers.ModelSerializer): published_time = serializers.SerializerMethodField() # 自定义一个字段 class Meta: model = models.Article fields = ['title', 'source', 'brief', 'view_num', 'comment_num', 'collect_num', 'published_time', 'head_img', 'content', 'agree_num'] # 将自定义的字段放到fields中,通过fields='__all__'也可以 depth = 1 # 表示深度 def get_published_time(self, obj): # 定义方法,def get_自定义的字段名: time = (now() - obj.pub_date).days week, day = divmod(time, 7) hour, min = divmod(int((now() - obj.pub_date).seconds), 3600) # print(week) # print(day) if week > 1: return '%s周前' % week elif day > 1: return '%s天前' % day elif hour > 1: return '%s小时前' % hour elif min > 1: return '%s小时前' % min else: return '刚刚'
5、指定生成URL

class UsersSerializer(serializers.ModelSerializer): # group = serializers.HyperlinkedIdentityField(view_name='detail') #让group的结果为按照urls中name为detail的url反向生成url 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}) #要反向生成url时,必须带上这个context,否则报错 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'), url(r'^users5/(?P<pk>.*)', views.UserView5.as_view(), name='detail'), #必须叫pk ]
6、全部自动生成URL

1 class UsersSerializer(serializers.HyperlinkedModelSerializer): #继承他自动生成 2 class Meta: 3 model = models.UserInfo 4 fields = "__all__" 5 6 # fields = ['id','name','pwd'] 7 8 class UsersView(APIView): 9 def get(self,request,*args,**kwargs): 10 self.dispatch 11 # 方式一: 12 # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title") 13 # return Response(user_list) 14 15 # 方式二之多对象 16 user_list = models.UserInfo.objects.all() 17 # [obj1,obj2,obj3] 18 ser = UsersSerializer(instance=user_list,many=True,context={'request':request}) 19 return Response(ser.data)
全部自动生成时,默认使用的反向生成的名字是 '字段名-detail',
exclude排除某字段,其余保留
四、请求数据验证:
a、自己手写

1 class PasswordValidator(object): 2 def __init__(self, base): 3 self.base = base 4 5 def __call__(self, value): 6 if value != self.base: 7 message = '用户输入的值必须是 %s.' % self.base 8 raise serializers.ValidationError(message) 9 10 def set_context(self, serializer_field): 11 """ 12 This hook is called by the serializer instance, 13 prior to the validation call being made. 14 """ 15 # 执行验证之前调用,serializer_fields是当前字段对象 16 pass 17 18 class UsersSerializer(serializers.Serializer): 19 name = serializers.CharField(min_length=6) 20 pwd = serializers.CharField(error_messages={'required': '密码不能为空'}, validators=[PasswordValidator('666')])
b、基于model

1 class PasswordValidator(object): 2 def __init__(self, base): 3 self.base = base 4 5 def __call__(self, value): 6 if value != self.base: 7 message = '用户输入的值必须是 %s.' % self.base 8 raise serializers.ValidationError(message) 9 10 def set_context(self, serializer_field): 11 """ 12 This hook is called by the serializer instance, 13 prior to the validation call being made. 14 """ 15 # 执行验证之前调用,serializer_fields是当前字段对象 16 pass 17 18 class UsersSerializer(serializers.ModelSerializer): 19 class Meta: 20 model = models.UserInfo 21 fields = "__all__" 22 #自定义验证规则 23 extra_kwargs = { 24 'name': {'min_length': 6}, 25 'pwd': {'validators': [PasswordValidator(666), ]} 26 }
使用

1 class UsersView(APIView): 2 def get(self,request,*args,**kwargs): 3 self.dispatch 4 # 方式一: 5 # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title") 6 # return Response(user_list) 7 8 # 方式二之多对象 9 user_list = models.UserInfo.objects.all() 10 # [obj1,obj2,obj3] 11 ser = UsersSerializer(instance=user_list,many=True,context={'request':request}) 12 return Response(ser.data) 13 14 def post(self,request,*args,**kwargs): 15 ser = UsersSerializer(data=request.data) 16 if ser.is_valid(): 17 print(ser.validated_data) 18 else: 19 print(ser.errors) 20 return Response('...')
钩子函数
def validate_字段(self,validated_value): raise ValidationError(detail='xxxxxx') return validated_value