一、版本
程序也来越大时,可能通过版本不同做不同的处理
没用rest_framework之前,我们可以通过以下这样的方式去获取。
代码语言:javascript复制 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
代码语言:javascript复制REST_FRAMEWORK = {
'DEFAULT_VERSION': 'v1', # 默认版本
'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本
'VERSION_PARAM': 'version' # URL中获取值的key
}
代码语言:javascript复制from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r'^test/', TestView.as_view(),name='test'),
]
代码语言:javascript复制#!/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/
代码语言:javascript复制REST_FRAMEWORK = {
'DEFAULT_VERSION': 'v1', # 默认版本
'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本
'VERSION_PARAM': 'version' # URL中获取值的key
}
代码语言:javascript复制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'),
]
代码语言:javascript复制#!/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
代码语言:javascript复制REST_FRAMEWORK = {
'DEFAULT_VERSION': 'v1', # 默认版本
'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本
'VERSION_PARAM': 'version' # URL中获取值的key
}
代码语言:javascript复制from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r'^test/', TestView.as_view(), name='test'),
]
代码语言:javascript复制#!/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
代码语言:javascript复制ALLOWED_HOSTS = ['*']
REST_FRAMEWORK = {
'DEFAULT_VERSION': 'v1', # 默认版本
'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本
'VERSION_PARAM': 'version' # URL中获取值的key
}
代码语言:javascript复制from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r'^test/', TestView.as_view(), name='test'),
]
代码语言:javascript复制#!/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请求,响应内容')
代码语言:javascript复制#分发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里面配置一下
代码语言:javascript复制ALLOWED_HOSTS = ['*']
e. 基于django路由系统的namespace
如:example.com/v1/users/
代码语言:javascript复制REST_FRAMEWORK = {
'DEFAULT_VERSION': 'v1', # 默认版本
'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本
'VERSION_PARAM': 'version' # URL中获取值的key
}
代码语言:javascript复制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')),
]
代码语言:javascript复制#!/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/
代码语言:javascript复制#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实现的,当前版本不一样的时候可以用这种方式
代码语言:javascript复制 from django.urls import reverse
url = reverse(viewname='users-list',kwargs={'version':'v2'}) #指定的是v2就是v2,当你路径中输入v1的时候还是v2的路径
print(url) #/api/v2/users/
f. 全局使用
代码语言:javascript复制REST_FRAMEWORK = {
'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning",
'DEFAULT_VERSION': 'v1',
'ALLOWED_VERSIONS': ['v1', 'v2'],
'VERSION_PARAM': 'version'
}
注:在配置的时候
代码语言:javascript复制REST_FRAMEWORK = {
'VERSION_PARAM':'version',
'DEFAULT_VERSION':'v1',
'ALLOWED_VERSIONS':['v1','v2'],
# 'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.HostNameVersioning"
#如果加上这个配置就不用versioning_class = QueryParameterVersioning这样再指定了,
二、解析器(parser) :reqest.data取值的时候才执行
对请求的数据进行解析:是针对请求体进行解析的。表示服务器可以解析的数据格式的种类
django中的发送请求
代码语言:javascript复制#如果是这样的格式发送的数据,在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的缺点
代码语言:javascript复制 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的请求体
代码语言:javascript复制from django.conf.urls import url, include
from web.views.s5_parser import TestView
urlpatterns = [
url(r'test/', TestView.as_view(), name='test'),
]
代码语言:javascript复制#!/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 的请求体
代码语言:javascript复制from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r'test/', TestView.as_view(), name='test'),
]
代码语言:javascript复制#!/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的请求体
代码语言:javascript复制from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r'test/', TestView.as_view(), name='test'),
]
代码语言:javascript复制#!/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请求,响应内容')
代码语言:javascript复制<!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. 仅上传文件
代码语言:javascript复制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 ]
代码语言:javascript复制 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请求,响应内容')
代码语言:javascript复制 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
代码语言:javascript复制from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r'test/', TestView.as_view(), name='test'),
]
代码语言:javascript复制#!/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.全局使用
代码语言:javascript复制REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES':[
'rest_framework.parsers.JSONParser'
'rest_framework.parsers.FormParser'
'rest_framework.parsers.MultiPartParser'
]
}
代码语言:javascript复制from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r'test/', TestView.as_view(), name='test'),
]
代码语言:javascript复制#!/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
因为
代码语言:javascript复制 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
代码语言:javascript复制 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中
代码语言:javascript复制 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. 自定义字段
代码语言:javascript复制from django.conf.urls import url, include
from web.views.s6_serializers import TestView
urlpatterns = [
url(r'test/', TestView.as_view(), name='test'),
]
代码语言:javascript复制#!/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自动生成字段
代码语言:javascript复制from django.conf.urls import url, include
from web.views.s6_serializers import TestView
urlpatterns = [
url(r'test/', TestView.as_view(), name='test'),
]
代码语言:javascript复制#!/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
代码语言:javascript复制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'),
]
代码语言:javascript复制#!/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
代码语言:javascript复制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'),
]
代码语言:javascript复制#!/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、基本操作
代码语言:javascript复制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)
代码语言:javascript复制 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、跨表
代码语言:javascript复制 x1 = serializers.CharField(source='group.mu.name')
代码语言:javascript复制 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、复杂序列化
自定义类和方法
解决方案一:
代码语言:javascript复制 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
解决方案二:
代码语言:javascript复制 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
解决方案三(推荐使用)
代码语言:javascript复制 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
代码语言:javascript复制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中没有的字段时,可以采用以下方式
代码语言:javascript复制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
代码语言:javascript复制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)
代码语言:javascript复制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
代码语言:javascript复制 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、自己手写
代码语言:javascript复制 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
代码语言:javascript复制 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 }
使用
代码语言:javascript复制 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('...')
钩子函数
代码语言:javascript复制def validate_字段(self,validated_value):
raise ValidationError(detail='xxxxxx')
return validated_value