1、rest framework的版本使用git
一、版本能夠寫在URL中,經過GET傳參,如 http://127.0.0.1:8082/api/users/?version=v1django
(1)自定義類獲取版本信息:json
from django.http import JsonResponse from rest_framework.views import APIView class ParamVersion(object): """獲取版本""" def determine_version(self, request, *args, **kwargs): version = request.query_params.get("version") # 獲取請求裏面的版本信息 return version class UsersView(APIView): """用戶中心""" versioning_class = ParamVersion # 獲取版本信息 def get(self, request, *args, **kwargs): res = {"code": 1000, "msg": None, "data": None} version = request.version print(version) return JsonResponse(res)
(2)經過內置類來獲取版本api
from django.http import JsonResponse from rest_framework.views import APIView from rest_framework.versioning import QueryParameterVersioning class UsersView(APIView): """用戶中心""" versioning_class = QueryParameterVersioning # 獲取版本信息 def get(self, request, *args, **kwargs): res = {"code": 1000, "msg": None, "data": None} version = request.version print(version) return JsonResponse(res)
在項目的settings中進行參數配置:app
二、也能夠寫在URL的路徑中,如 http://127.0.0.1:8082/api/v1/users/ide
能夠經過內置類來獲取:函數
from django.http import JsonResponse from rest_framework.views import APIView from rest_framework.versioning import URLPathVersioning class UsersView(APIView): """用戶中心""" versioning_class = URLPathVersioning # 獲取版本信息 def get(self, request, *args, **kwargs): res = {"code": 1000, "msg": None, "data": None} version = request.version print(version) return JsonResponse(res)
推薦使用第二種方法來配置版本信息。post
三、能夠將版本類寫到配置文件中,進行全局控制:ui
在項目的settings中進行設置:this
from django.http import JsonResponse from rest_framework.views import APIView class UsersView(APIView): """用戶中心""" def get(self, request, *args, **kwargs): res = {"code": 1000, "msg": None, "data": None} version = request.version # 獲取版本 print(version) return JsonResponse(res)
四、源碼流程
路由→as_view()→rest framework的dispatch()→initial()→determine_version()
能夠經過request.version獲取版本信息
經過request.versioning_scheme獲取處理版本的對象,能夠利用這個對象調用reverse()方法來反向生成url:
from django.conf.urls import url from api import views urlpatterns = [ url(r'^(?P<version>[v1|v2]+)/users/$', views.UsersView.as_view(), name="userView"), ]
from django.http import JsonResponse from rest_framework.views import APIView class UsersView(APIView): """用戶中心""" def get(self, request, *args, **kwargs): res = {"code": 1000, "msg": None, "data": None} version = request.version # 獲取版本 scheme = request.versioning_scheme # 處理版本的對象 # 反向生成URL url = scheme.reverse(viewname="userView", request=request) print(url) return JsonResponse(res)
2、解析器
解析器:對請求體的數據進行解析
一、Django的解析器
from django.core.handlers.wsgi import WSGIRequest
在Django內部會跟據不一樣的狀況將request.body裏面的數據解析到request.POST:
因此只有當 Content_type='application/x-www-form-urlencoded' 時,纔會去解析request.body裏面的數據,另外,數據格式必須是 name=amy&age=18 這種格式才能被解析,
基於如上兩個條件才能使得request.POST有值。
二、rest framework的解析器
一、示例
from django.http import JsonResponse from rest_framework.views import APIView from rest_framework.parsers import JSONParser class ExampleView02(APIView): """""" parser_classes = [JSONParser] # 解析器類JSONParser:表示容許用戶發送json格式的數據{"name":"amy", "age":18} def post(self, request, *args, **kwargs): res = {"code": 1000, "msg": None, "data": None} data = request.data # 獲取解析後的數據 res["data"] = data return JsonResponse(res)
JSONParser類只能解析Content-type爲applicaton/json的數據,
FormParser類只能解析Content-type爲applicaton/x-www-form-urlencoded的數據,
三、rest framework的解析器源碼流程
執行dispatch()中的initialize_request()方法:
在視圖中調用requst.data觸發:
request的data方法調用_load_data_and_files():
以JSONParser類爲例:
3、rest framework序列化處理數據
一、示例1 序列化類的使用
from django.db import models class UserGroup(models.Model): title = models.CharField(max_length=32) class UserInfo(models.Model): user_type_choices = ( (1, "普通用戶"), (2, "vip"), (3, "svip"), ) user_type = models.IntegerField(choices=user_type_choices) username = models.CharField(max_length=32, unique=True) password = models.CharField(max_length=64) group = models.ForeignKey(to="UserGroup", on_delete=models.CASCADE, null=True, blank=True) roles = models.ManyToManyField(to="Role", blank=True) class UserToken(models.Model): user = models.OneToOneField(to="UserInfo") token = models.CharField(max_length=64) class Role(models.Model): title = models.CharField(max_length=32) class Order(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=32) price = models.DecimalField(max_digits=5, decimal_places=2) create_time = models.DateTimeField(auto_now_add=True) user = models.ForeignKey(to="UserInfo", on_delete=models.CASCADE, null=True, blank=True)
from django.conf.urls import url from api import views urlpatterns = [ url(r'^(?P<version>[v1|v2]+)/roles/$', views.RolesView.as_view()), ]
import json from django.shortcuts import HttpResponse from rest_framework.views import APIView from rest_framework import serializers from api import models class RolesSerializer(serializers.Serializer): """對獲取的數據進行序列化操做""" # 要與數據表中的字段向對應 id = serializers.CharField() title = serializers.CharField() class RolesView(APIView): """獲取角色""" def get(self, request, *args, **kwargs): # 方法一: # roles = models.Role.objects.all().values("id", "title") # roles = list(roles) # res = json.dumps(roles, ensure_ascii=False) # 方法二:使用序列化類 # roles = models.Role.objects.all() # # 實例化序列化類 若是是對多條數據進行序列化要設置 many=True # serl = RolesSerializer(instance=roles, many=True) # res = serl.data # 獲取序列化後的結果 # res = json.dumps(res, ensure_ascii=False) role = models.Role.objects.all().first() # 實例化序列化類 若是是對一條數據進行序列化要設置 many=False serl = RolesSerializer(instance=role, many=False) res = serl.data # 獲取序列化後的結果 res = json.dumps(res, ensure_ascii=False) return HttpResponse(res)
二、序列化自定義字段
from django.conf.urls import url from api import views urlpatterns = [ url(r'^(?P<version>[v1|v2]+)/userInfo/$', views.UserInfoView.as_view()), ]
import json from django.shortcuts import HttpResponse from rest_framework.views import APIView from rest_framework import serializers from api import models class UserInfoSerializer(serializers.Serializer): """對獲取的數據進行序列化操做""" username = serializers.CharField() password = serializers.CharField() user_type = serializers.CharField(source="get_user_type_display") # 獲取choices字段的文本 group = serializers.CharField(source="group.title") # 獲取ForeignKey字段 roles = serializers.SerializerMethodField() # 自定義顯示ManyToMany字段 def get_roles(self, row): """獲取角色對象信息""" role_obj_list = row.roles.all() res = [] for item in role_obj_list: res.append({"id": item.id, "title": item.title}) return res class UserInfoView(APIView): """獲取用戶信息""" def get(self, request, *args, **kwargs): users = models.UserInfo.objects.all() serl = UserInfoSerializer(instance=users, many=True) res = json.dumps(serl.data, ensure_ascii=False) return HttpResponse(res)
三、除了繼承Serializer類實現序列化,還可使用ModelSerializer類來實現。ModelSerializer繼承了Serializer
import json from django.shortcuts import HttpResponse from rest_framework.views import APIView from rest_framework import serializers from api import models class UserInfoSerializer(serializers.ModelSerializer): """對獲取的數據進行序列化操做""" class Meta: model = models.UserInfo fields = "__all__" # 對全部的字段作序列化 class UserInfoView(APIView): """獲取用戶信息""" def get(self, request, *args, **kwargs): users = models.UserInfo.objects.all() serl = UserInfoSerializer(instance=users, many=True) res = json.dumps(serl.data, ensure_ascii=False) return HttpResponse(res)
這種方式生成的數據比較」簡陋「,能夠根據需求定製:
class UserInfoSerializer(serializers.ModelSerializer): """對獲取的數據進行序列化操做""" user_type = serializers.CharField(source="get_user_type_display") group = serializers.CharField(source="group.title") roles = serializers.SerializerMethodField() # 自定義顯示ManyToMany字段 def get_roles(self, row): """獲取角色對象信息""" role_obj_list = row.roles.all() res = [] for item in role_obj_list: res.append({"id": item.id, "title": item.title}) return res class Meta: model = models.UserInfo fields = ["id", "username", "password", "user_type", "group", "roles"] class UserInfoView(APIView): """獲取用戶信息""" def get(self, request, *args, **kwargs): users = models.UserInfo.objects.all() serl = UserInfoSerializer(instance=users, many=True) res = json.dumps(serl.data, ensure_ascii=False) return HttpResponse(res)
四、序列化深度控制
自動序列化實現連表操做
class UserInfoSerializer(serializers.ModelSerializer): """對獲取的數據進行序列化操做""" class Meta: model = models.UserInfo fields = "__all__" depth = 1 # 深度控制 建議取0~10層,層數越多響應速度也會受到影響 class UserInfoView(APIView): """獲取用戶信息""" def get(self, request, *args, **kwargs): users = models.UserInfo.objects.all() serl = UserInfoSerializer(instance=users, many=True) res = json.dumps(serl.data, ensure_ascii=False) return HttpResponse(res)
五、序列化生成HyperMediaLink
需求:經過查看用戶信息頁面獲取到查看分組信息的URL
from django.conf.urls import url from api import views urlpatterns = [ url(r'^(?P<version>[v1|v2]+)/userInfo/$', views.UserInfoView.as_view()), url(r'^(?P<version>[v1|v2]+)/group/(?P<pk>\d+)$', views.GroupView.as_view(), name="groupView"), ]
import json from django.shortcuts import HttpResponse from rest_framework.views import APIView from rest_framework import serializers from api import models class GroupSerializer(serializers.ModelSerializer): """對獲取的數據進行序列化操做""" class Meta: model = models.UserGroup fields = "__all__" class UserInfoSerializer(serializers.ModelSerializer): """對獲取的數據進行序列化操做""" # 反向生成查看group的URL group = serializers.HyperlinkedIdentityField(view_name="groupView", lookup_field="group_id", lookup_url_kwarg="pk") class Meta: model = models.UserInfo fields = ["id", "username", "password", "user_type", "group"] class GroupView(APIView): """獲取分組信息""" def get(self, request, *args, **kwargs): pk = kwargs.get("pk") group_obj = models.UserGroup.objects.filter(id=pk).first() serl = GroupSerializer(instance=group_obj, many=False) res = json.dumps(serl.data, ensure_ascii=False) return HttpResponse(res) class UserInfoView(APIView): """獲取用戶信息""" def get(self, request, *args, **kwargs): users = models.UserInfo.objects.all() serl = UserInfoSerializer(instance=users, many=True, context={"request": request}) res = json.dumps(serl.data, ensure_ascii=False) return HttpResponse(res)
六、序列化源碼流程
若是是處理QuerySet數據,就會執行many_init()方法:
至關於在內部,若是是處理對象(一條數據),就使用Serializer進行處理;若是是處理QuerySet(多條數據),就用ListSerializer處理。
實例化完成後,能夠經過「對象名.data」方法 獲取數據:
父類的data方法:
若是是處理對象(一條數據),就到Serializer類裏面找to_representation()方法;若是是處理QuerySet(多條數據),就去ListSerializer裏面找。
get_attribute()方法的具體實現:
循環字段列表獲取字段對應的值:
獲取instance對象對應的字段的屬性值,而後把這個屬性值賦值給instance,而後繼續循環,直到instance從字段裏面獲取不到值爲止,即取數據表中真正的數值,
如 UserInfo 表中有外鍵group,想要獲取到group字段對應的表對象的title字段:group = serializers.CharField(source="group.title"),則此時attrs=['group', 'title'],
第一輪循環時:instance=getattr(UserInfo object,group)=UserGroup object,
第二輪循環時instance=getattr(UserGroup object,title)=A組,此時便經過外鍵獲取到UserGroup表中的title字段的值了。
當字段是一個能夠被調用的對象(如函數或方法)時,就在這個字段後面加上「()」,直接執行這個函數或者方法,將返回值賦值給instance。
如 獲取一個choices字段的文本:user_type=serializers.CharField(source="get_user_type_display") ,這個get_user_type_display就是一個可調用的方法。
對於字段是serializers.HyperlinkedIdentityField()對象的時候執行的to_representation()方法:
因此,咱們在使用HyperlinkedIdentityField()的時候要傳遞參數:
4、rest framework序列化驗證用戶請求數據
一、自定義類 驗證用戶請求數據
from django.conf.urls import url from api import views urlpatterns = [ url(r'^(?P<version>[v1|v2]+)/userGroup/$', views.UserGroupView.as_view()), ]
import json from django.shortcuts import HttpResponse from rest_framework.views import APIView from rest_framework import serializers from api import models class MyValidator(object): """自定製校驗規則""" def __init__(self, base): self.base = base def __call__(self, value): # 設置一個必須以self.base開頭的規則 if not value.startswith(self.base): message = "this field must start with %s." % self.base raise serializers.ValidationError(message) def set_context(self, serializer_field): pass class UserGroupSerializer(serializers.Serializer): title = serializers.CharField( error_messages={"required": "標題不能爲空"}, validators=[MyValidator("a-")], ) # 校驗的字段:title class UserGroupView(APIView): """驗證用戶請求數據""" def post(self, request, *args, **kwargs): # request.data :用戶提交過來的數據 serl = UserGroupSerializer(data=request.data) # 若是請求數據是合法的,就獲取到的數據,不然打印錯誤信息 if serl.is_valid(): print(serl.validated_data["title"]) else: print(serl.errors) return HttpResponse("xxx")
二、源碼
在Serializer類中實現了請求數據校驗:
from django.conf.urls import url from api import views urlpatterns = [ url(r'^(?P<version>[v1|v2]+)/userGroup/$', views.UserGroupView.as_view()), ]
from django.shortcuts import HttpResponse from rest_framework.views import APIView from rest_framework import serializers from api import models class UserGroupSerializer(serializers.Serializer): title = serializers.CharField( error_messages={"required": "標題不能爲空"}, # validators=[MyValidator("a-")], ) # 校驗的字段:title def validate_title(self, value): """自定義title字段鉤子方法""" if not value.startswith("a-"): message = "值必須以'a-'開頭." raise serializers.ValidationError(message) return value class UserGroupView(APIView): """驗證用戶請求數據""" def post(self, request, *args, **kwargs): # request.data :用戶提交過來的數據 serl = UserGroupSerializer(data=request.data) # 若是請求數據是合法的,就獲取到的數據,不然打印錯誤信息 if serl.is_valid(): print(serl.validated_data["title"]) else: print(serl.errors) return HttpResponse("xxx")