Restful Framework (三)

目錄

1、版本html

2、解析器python

3、序列化web

4、請求數據驗證數據庫


1、版本

回到頂部django

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

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

 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實現一下,有兩種方式api

一、基於url的方式

#基於url傳參的形式
     versioning_class = QueryParameterVersioning
    #http://127.0.0.1:8080/api/users/?version=v2
    
#基於url的形式
  versioning_class = URLPathVersioning   #http://127.0.0.1:8080/api/v1/users/

具體步驟服務器

1 REST_FRAMEWORK = { 2     'DEFAULT_VERSION': 'v1',  #默認的版本
3     'ALLOWED_VERSIONS': ['v1','v2'],  #容許的版本
4     'VERSION_PARAM': 'version', 5 }
一、配置
1 from django.conf.urls import url,include 2 from django.contrib import admin 3 
4 
5 urlpatterns = [ 6     url(r'^admin/', admin.site.urls), 7     url(r'^api/(?P<version>[v1|v2]+)/', include('api.urls'), name='users-list'), 8 ]
urls.py
1 from api import views 2 urlpatterns = [ 3     # url(r'^users/', views.UserView.as_view()),
4     url(r'^users/', views.UserView1.as_view()), 5 
6 ]
urls.py
 1 class UserView1(APIView):  2     #基於url傳參的形式
 3     # versioning_class = QueryParameterVersioning
 4     #http://127.0.0.1:8080/api/users/?version=v2
 5 
 6     #基於url的形式
 7     #http://127.0.0.1:8080/api/v1/users/
 8     versioning_class = URLPathVersioning  9     def get(self,request,*args,**kwargs): 10         # self.dispatch
11         print(request.version)  #打印的是版本
12         print(request.versioning_scheme)  #打印的是對象
13         if request.version=='v2': 14             return Response('我是版本二') 15         elif request.version=='v1': 16             return Response('我是版本一') 17         else: 18             return Response('去去去')
views.py

注:在配置的時候restful

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

 

附加:restful提供的反向生成

#http://127.0.0.1:8080/api/v1/users/

 1 #urls.py 
 2 #分發路由
 3 urlpatterns = [  4     url(r'^admin/', admin.site.urls),  5     url(r'^api/(?P<version>[v1|v2]+)/', include('api.urls')),  6 ]  7 
 8 #api.urls.py
 9 urlpatterns = [ 10     url(r'^users/', views.UserView1.as_view(), name='users-list'), 11 ] 12 
13 #views.py 
14 導入類 15 from rest_framework.reverse import reverse 16 url = request.versioning_scheme.reverse(viewname='users-list',request=request) 17         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/

二、基於子域名傳參

 1 #分發url
 2             urlpatterns = [  3                 #url(r'^admin/', admin.site.urls),
 4                 url(r'^api/', include('api.urls')),  5  ]  6 
 7             urlpatterns = [  8                 url(r'^users/', views.UsersView.as_view(),name='u'),  9  ] 10             
11             
12             class UsersView(APIView): 13                 
14                 def get(self,request,*args,**kwargs): 15  self.dispatch 16                     print(request.version) # QueryParameterVersioning().detemiin_version()
17                     print(request.versioning_scheme) # QueryParameterVersioning()
18 
19             
20             REST_FRAMEWORK = { 21                 'VERSION_PARAM':'version', 22                 'DEFAULT_VERSION':'v1', 23                 'ALLOWED_VERSIONS':['v1','v2'], 24                 'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.HostNameVersioning"
25  } 26             
27             # C:\Windows\System32\drivers\etc
28             # vim /etc/hosts
29             127.0.0.1 v1.luffy.com 30             127.0.0.1 v2.luffy.com 31             
32             #配置ALLOWED_HOSTS = ['*']
基於子域名傳參

 

 若是遇到這樣的錯誤

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

ALLOWED_HOSTS = ['*']

 

2、解析器: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('...')
具體講解

傳上傳文件

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

全局使用

1 REST_FRAMEWORK = { 2     'DEFAULT_PARSER_CLASSES':[ 3         'rest_framework.parsers.JSONParser'
4         'rest_framework.parsers.FormParser'
5         'rest_framework.parsers.MultiPartParser'
6  ] 7 
8 }
settings.py

3、序列化

回到頂部

序列化用於對用戶請求數據進行驗證和數據進行序列化(爲了解決queryset序列化問題)。

那什麼是序列化呢?序列化就是把對象轉換成字符串,反序列化就是把字符串轉換成對象

models.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)

一、基本操做

 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

 1 class UsersSerializer(serializers.ModelSerializer):  2 x1 = serializers.CharField(source='name')  3 group = serializers.HyperlinkedIdentityField(view_name='detail')  4 class Meta:  5     
 6     model = models.UserInfo  7     # fields = "__all__"
 8     fields = ['name','pwd','group','x1']  #自定義字段的時候注意要指定source,scource裏面的數據必須是數據庫有的數據
 9     depth = 1 #表示深度
10 
11 
12 class UsersView(APIView): 13     def get(self,request,*args,**kwargs): 14  self.dispatch 15         # 方式一:
16         # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title")
17         # return Response(user_list)
18 
19         # 方式二之多對象
20         user_list = models.UserInfo.objects.all() 21         # [obj1,obj2,obj3]
22         ser = UsersSerializer(instance=user_list,many=True) 23         return Response(ser.data)
Views.py

五、生成URL

 1 class UsersSerializer(serializers.ModelSerializer):  #  2     group = serializers.HyperlinkedIdentityField(view_name='detail')  3     class Meta:  4         model = models.UserInfo  5         fields = "__all__"
 6         fields = ['name', 'pwd','group']  7         depth = 1
 8 
 9 
10 class UsersView(APIView): 11     def get(self,request,*args,**kwargs): 12  self.dispatch 13         # 方式一:
14         # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title")
15         # return Response(user_list)
16 
17         # 方式二之多對象
18         user_list = models.UserInfo.objects.all() 19         # [obj1,obj2,obj3]
20         ser = UsersSerializer(instance=user_list,many=True,context={'request':request}) 21         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'), #吧users4的group的值反向生成users5的url url(r'^users5/(?P<pk>.*)', views.UserView5.as_view(), name='detail'),  #必須叫pk
    # url(r'^users4/(?P<pk>.*)', views.UserView4.as_view(), name='detail'),
]

六、全局生成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

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