目錄
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)
如今咱們來用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 ]
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 ]
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('去去去')
注:在配置的時候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)
咱們本身用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 ]
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請求,響應內容')
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>
全局使用
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 }
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)
二、跨表
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)
三、複雜序列化
解決方案一:
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
解決方案二:
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
解決方案三(推薦使用)
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
四、基於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)
五、生成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)
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)
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')])
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 }
使用
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('...')
鉤子函數
def validate_字段(self,validated_value): raise ValidationError(detail='xxxxxx') return validated_value