Django Rest Framework(版本、解析器、序列化、数据验证)
一、版本
程序也来越大时,可能通过版本不同做不同的处理
没用rest_framework之前,我们可以通过以下这样的方式去获取。
- 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实现一下
a. 基于url的get传参方式
如:/users?version=v1
- REST_FRAMEWORK = {
- 'DEFAULT_VERSION': 'v1', # 默认版本
- 'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本
- 'VERSION_PARAM': 'version' # URL中获取值的key
- }
settings.py
- from django.conf.urls import url, include
- from web.views import TestView
- urlpatterns = [
- url(r'^test/', TestView.as_view(),name='test'),
- ]
urls.py
- #!/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请求,响应内容')
views.py
b. 基于url的正则方式
如:/v1/users/
- REST_FRAMEWORK = {
- 'DEFAULT_VERSION': 'v1', # 默认版本
- 'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本
- 'VERSION_PARAM': 'version' # URL中获取值的key
- }
settings.py
- 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'),
- ]
urls.py
- #!/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请求,响应内容')
views.py
c. 基于 accept 请求头方式
如:Accept: application/json; version=1.0
- REST_FRAMEWORK = {
- 'DEFAULT_VERSION': 'v1', # 默认版本
- 'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本
- 'VERSION_PARAM': 'version' # URL中获取值的key
- }
settings.py
- from django.conf.urls import url, include
- from web.views import TestView
- urlpatterns = [
- url(r'^test/', TestView.as_view(), name='test'),
- ]
urls.py
- #!/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请求,响应内容')
views.py
d. 基于主机名方法
如:v1.example.com
- ALLOWED_HOSTS = ['*']
- REST_FRAMEWORK = {
- 'DEFAULT_VERSION': 'v1', # 默认版本
- 'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本
- 'VERSION_PARAM': 'version' # URL中获取值的key
- }
settings.py
- from django.conf.urls import url, include
- from web.views import TestView
- urlpatterns = [
- url(r'^test/', TestView.as_view(), name='test'),
- ]
urls.py
- #!/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请求,响应内容')
views.py
- #分发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:\Windows\System32\drivers\etc
- # 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
- }
settings.py
- 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')),
- ]
urls.py
- #!/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请求,响应内容')
views.py
#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)
restfoamework反向解析
我们自己用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'
- }
settings.py
注:在配置的时候
- 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的缺点
- 客户端:
- 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('...')
具体讲解
根据请求头 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'),
- ]
urls.py
- #!/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请求,响应内容')
views.py
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'),
- ]
urls.py
- #!/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请求,响应内容')
views.py
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'),
- ]
urls.py
- #!/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请求,响应内容')
views.py
- <!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>
upload.html
d. 仅上传文件
- from django.conf.urls import url, include
- from web.views import TestView
- urlpatterns = [
- url(r'test/(?P<filename>[^/]+)', TestView.as_view(), name='test'),
- ]
urls.py
- #!/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请求,响应内容')
views.py
- <!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>
upload.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'),
- ]
urls.py
- #!/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请求,响应内容')
views.py
f.全局使用
- REST_FRAMEWORK = {
- 'DEFAULT_PARSER_CLASSES':[
- 'rest_framework.parsers.JSONParser'
- 'rest_framework.parsers.FormParser'
- 'rest_framework.parsers.MultiPartParser'
- ]
- }
settings.py
- from django.conf.urls import url, include
- from web.views import TestView
- urlpatterns = [
- url(r'test/', TestView.as_view(), name='test'),
- ]
urls.py
- #!/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请求,响应内容')
views.py
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
APIView.dispatch
- 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中
Request.__init__
- 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)
Request.__getattar__
三、序列化
序列化用于对用户请求数据进行验证和数据进行序列化(为了解决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'),
- ]
urls.py
- #!/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('')])
- 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请求,响应内容')
views.py
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'),
- ]
urls.py
- #!/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请求,响应内容')
views.py
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'),
- ]
urls.py
- #!/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请求,响应内容')
views.py
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'),
- ]
urls.py
- #!/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请求,响应内容')
views.py
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)
models.py
- 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)
views.py
2、跨表
- x1 = serializers.CharField(source='group.mu.name')
如果你想跨表拿你任何需要的数据,都可以用上面的这种操作,内部做判断,如果可用内部就加括号调用了
- 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)
Views.py
3、复杂序列化
自定义类和方法
解决方案一:
- 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
Views.py
解决方案二:
- 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
Views.py
解决方案三(推荐使用)
- 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
Views.py
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)
Views.py
当我们想定义一个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)
views.py
- 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
- 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)
views.py
全部自动生成时,默认使用的反向生成的名字是 '字段名-detail',
exclude排除某字段,其余保留
四、请求数据验证:
a、自己手写
- 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('')])
views.py
b、基于model
- 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.ModelSerializer):
- class Meta:
- model = models.UserInfo
- fields = "__all__"
- #自定义验证规则
- extra_kwargs = {
- 'name': {'min_length': 6},
- 'pwd': {'validators': [PasswordValidator(666), ]}
- }
views.py
使用
- 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('...')
viewS.py
钩子函数
- def validate_字段(self,validated_value):
- raise ValidationError(detail='xxxxxx')
- return validated_value
Django Rest Framework(版本、解析器、序列化、数据验证)的更多相关文章
- Django Rest framework 之 解析器
RESTful 规范 django rest framework 之 认证(一) django rest framework 之 权限(二) django rest framework 之 节流(三) ...
- DRF Django REST framework 之 解析器(二)
引入 Django Rest framework帮助我们实现了处理application/json协议请求的数据,如果不使用DRF,直接从 request.body 里面拿到原始的客户端请求的字节数据 ...
- Django Rest Framework之解析器
基本代码结构 urls.py: from django.conf.urls import url, include from web.views.s5_parser import TestView u ...
- Django REST framework的解析器与渲染器
解析器 解析器的作用 解析器的作用就是服务端接收客户端传过来的数据,把数据解析成自己可以处理的数据.本质就是对请求体中的数据进行解析. 在了解解析器之前,我们要先知道Accept以及ContentTy ...
- Django REST framework 中文教程1:序列化
建立环境 在我们做任何事情之前,我们将使用virtualenv创建一个新的虚拟环境.这将确保我们的包配置与我们正在开展的任何其他项目保持良好的隔离. virtualenv envsource env/ ...
- Django rest framework(6)----序列化
目录 Django rest framework(1)----认证 Django rest framework(2)----权限 Django rest framework(3)----节流 Djan ...
- Django REST Framework - 分页 - 渲染器 - 解析器
为什么要使用分页? 我们数据表中可能会有成千上万条数据,当我们访问某张表的所有数据时,我们不太可能需要一次把所有的数据都展示出来,因为数据量很大,对服务端的内存压力比较大还有就是网络传输过程中耗时也会 ...
- day71:drf:API接口&Restful API规范&Django Rest Framework&drf中的序列化和反序列化功能
目录 1.web应用模式 2.API接口 3.Restful API规范 4.序列化 5.Django Rest Framework 1.drf的简单介绍 2.drf的特点 3.如何安装drf 4.d ...
- rest framework 之解析器
一.示例 1.api/urls.py from django.urls import path, re_path from api.views import UserView, ParserView ...
随机推荐
- WdatePicker日历控件动态设置属性参数值
首先吐槽一下需求人员给了我一个很坑的需求:WdatePicker日历控件里面选择的最小时间(minDate)的值是级联动态改变的,而且这个值要从数据库获取,这样子只能使用 ajax 来发起请求获取mi ...
- linux之nginx的安装
(一)这次是自己折腾服务器的环境,所以自己算是都装过一遍,在装的过程中也是在网上搜索,其实最后在公司运维的指导下知道自己安装出错在哪里的.不说了,直接说安装和问题 (二):首先从 http://ngi ...
- hdu 3118 Arbiter
http://acm.hdu.edu.cn/showproblem.php?pid=3118 题意:删除最少的边使图没有奇环 二分图的定义:如果顶点能分为两个互不相交的子集,则图为二分图 二分 ...
- java绝对路径和相对路径的理解
日常开发中引用东西经常会遇到路径问题,各种尝试,各种出错,其实只要理解了这两种路径,问题便迎刃而解. 在java中路径有两种表示方法:绝对路径和相对路径. (1) 相对路径:它以不带“\”的目录名表示 ...
- 【洛谷 P2764】 最小路径覆盖问题(最大流)
题目链接 首先有\(n\)条路径,每条路径就是一个点,然后尽量合并,答案就是点数-合并数. 套路拆点,源连入,出连汇,原有的边入出连. 最大流就是最大合并数,第一问解决. 然后怎么输出方案? 我是找到 ...
- 重载jquery on方法实现click事件在移动端的快速响应
额,这个标题取的还真是挺装的... 其实我想表达的是jquery click事件如何在移动端自动转换成touchstart事件. 因为移动端click事件会比touchstart事件慢几拍 移动设备某 ...
- 网络抓包wireshark(转)
下载地址:https://www.wireshark.org/download/win64/ 抓包应该是每个技术人员掌握的基础知识,无论是技术支持运维人员或者是研发,多少都会遇到要抓包的情况,用过 ...
- iTextSharp之pdfRead(两个文件文本内容的比较,指定页数的pdf截取,水印的添加)
using iTextSharp.text; using iTextSharp.text.pdf; using iTextSharp.text.pdf.parser; using System; us ...
- 简单实现JS上传图片预览功能
HTML代码 <div class="upload"> <input type="button" class="btn" ...
- 在flask中返回requests响应
在flask服务端,有时候需要使用requests请求其他url,并将响应返回回去.查阅了flask文档,About Responses,可以直接构造响应结果进行返回. If a tuple is r ...