Django Rest Framework(版本、解析器、序列化、數據驗證)

1、版本

程序也來越大時,可能經過版本不一樣作不一樣的處理html

沒用rest_framework以前,咱們能夠經過如下這樣的方式去獲取。python

 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實現一下web

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

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.0json

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

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 = ['*']
基於子域名傳參

若是遇到這樣的錯誤api

這是因爲沒有容許,解決辦法,在settings裏面配置一下服務器

ALLOWED_HOSTS = ['*']

 

 

e. 基於django路由系統的namespace

如:example.com/v1/users/app

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

 

 

 

2、解析器(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__

 

3、序列化

序列化用於對用戶請求數據進行驗證和數據進行序列化(爲了解決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

 

一、基本操做

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

二、跨表

 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

三、複雜序列化

自定義類和方法

解決方案一:

 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

四、基於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 '剛剛'

 

五、指定生成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
]

六、所有自動生成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排除某字段,其他保留

4、請求數據驗證:

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
                        
相關文章
相關標籤/搜索