• Django Rest Framework(版本、解析器、序列化、数据验证)


    一、版本

    程序也来越大时,可能通过版本不同做不同的处理

    没用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)
    View Code

    现在我们来用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: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
    }
    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的缺点

     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'),
    ]
    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. 仅上传文件

    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 ]
    urls.py
     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请求,响应内容')
    views.py
     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>
    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('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请求,响应内容')
    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
     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)
    views.py

    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)
    Views.py

    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
    Views.py

    解决方案二:

     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
    Views.py

    解决方案三(推荐使用)

     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     
    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

     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)
    views.py

    全部自动生成时,默认使用的反向生成的名字是 '字段名-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')])
    views.py

    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         }
    views.py

    使用

     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('...')
    viewS.py

    钩子函数

    def validate_字段(self,validated_value):
           raise ValidationError(detail='xxxxxx')
           return validated_value
                            
  • 相关阅读:
    Windows API
    c# 各类型数据库连接字符串格式
    [C#/C++]C#调用非托管DLL的APIs
    (F#) How to enable F# template working under Visual Studio 2010 Shell.
    ubuntu文件、目录操作基本命令
    javascript curry
    C#中组件与控件的主要区别是什么?
    下拉菜单
    js 尺寸和位置 笔记
    $.each
  • 原文地址:https://www.cnblogs.com/huchong/p/8450355.html
Copyright © 2020-2023  润新知