本篇內(nèi)容
補(bǔ)充:
關(guān)于實(shí)例化
v1 = ['view.xxx.path.Role','view.xxx.path.']
回顧
為什么用 django restframework?
關(guān)于認(rèn)證泣洞、權(quán)限、節(jié)流验辞,只需要寫類咖楣,就可以實(shí)現(xiàn)他們的方法返回值就可。
它幫我們實(shí)現(xiàn)了一些功能棍弄。
設(shè)計(jì)好的點(diǎn)?
單獨(dú)視圖配置和全局配置, 它的全局配置類似django中間件(importlib + 反射)披摄。
動(dòng)態(tài)配置可擴(kuò)展(用戶下單后,通過短信勇凭、郵件等提醒)疚膊。
關(guān)于它的原理:
基于 cbv,和 django 繼承的是同一個(gè)虾标。
請(qǐng)求進(jìn)來之后寓盗,先執(zhí)行 dispatch ( 五大功能,都是在 dispatch 里面實(shí)現(xiàn))璧函。
- 先執(zhí)行 as_view()
- view 函數(shù)
obj = cls()
傀蚌。。蘸吓。
return self.dispatch() - dispatch
- 封裝 request
- 版本
- 認(rèn)證 -> request.user -> 循環(huán)對(duì)象善炫,執(zhí)行_authticate
- 權(quán)限
- 節(jié)流
新 request對(duì)象(request,認(rèn)證相關(guān))
如果新 req 對(duì)象里面沒有你要的東西库继,就去舊的 request 里面找销部。
request.query_params
request.POST
request.Meta
今日內(nèi)容
- 版本摸航,
- 解析器,
- 序列化舅桩,
- 分頁
版本和解析器一旦配置好酱虎,基本可以不用再動(dòng)。
序列化:
- QuuerySet 類型 -> list,dict
- 請(qǐng)求驗(yàn)證
django form 組件也可以用在 restframework擂涛。
1. 為什么要有版本读串?
如果是version_1,就返回111
如果是version_2撒妈,就返回22
如果是version_3恢暖,就返回3
自己可以在 url 里面寫,然后 request 獲取再判斷就可以狰右。
但是d_rfw 已經(jīng)幫你做好了杰捂。
from rest_framework.versioning
versioning_class = QueryParameterVersioning # 這個(gè)就是幫你獲取 version 的值。
推薦:
versioning_class = UrlPathVersioning
版本源碼執(zhí)行流程
1. 進(jìn)來先到 dispatch()
def dispatch(self, request, *args, **kwargs):
2. self.initial(request, *args, **kwargs)
3. # 處理版本信息
# 這兩句是處理版本信息棋蚌,點(diǎn)擊self.determine_version
version, scheme = self.determine_version(request, *args, **kwargs)
request.version, request.versioning_scheme = version, scheme
4. def determine_version(self, request, *args, **kwargs):
if self.versioning_class is None:
return (None, None)
scheme = self.versioning_class()
return (scheme.determine_version(request, *args, **kwargs), scheme)
5. URLPathVersioning.determine_version(self, request, *args, **kwargs):
return version
6. 封裝到 request 中
request.version, request.versioning_scheme = version, scheme
7. 使用
class URLPathVersion(APIView):
# 關(guān)于 urlpath
versioning_class = URLPathVersioning
def get(self,request,*args,**kwargs):
print(request.version)
print(request.versioning_scheme)
2. 解析器
解析器對(duì)請(qǐng)求的數(shù)據(jù)解析
d_rdw 是針對(duì)請(qǐng)求頭解析嫁佳。
request.POST 不一定拿得到值,這個(gè)和 Content_Type 有關(guān)谷暮。
-
Content_Type : application/url-encoding
- 以這個(gè)發(fā)送的話蒿往,post 和 body 里面都會(huì)有值。
- 弊端:只有在 body 里可以拿到Bytes 類型的變態(tài)大叔湿弦。
d_rdw: parse_classes = [JONParse ,FormDataParse]
-
最常用的即 JSONParse
解析器小總結(jié):- 何時(shí)執(zhí)行瓤漏? 只有執(zhí)行 request.data/request.FILES/reqeust.POST
- 根據(jù) content_type頭,判斷是否支持颊埃。
- 何時(shí)執(zhí)行瓤漏? 只有執(zhí)行 request.data/request.FILES/reqeust.POST
2. rest framework解析器
請(qǐng)求的數(shù)據(jù)進(jìn)行解析:請(qǐng)求體進(jìn)行解析蔬充。表示服務(wù)端可以解析的數(shù)據(jù)格式的種類。
Content-Type: application/url-encoding.....
request.body
request.POST
Content-Type: application/json.....
request.body
request.POST
客戶端:
Content-Type: application/json
'{"name":"alex","age":123}'
服務(wù)端接收:
讀取客戶端發(fā)送的Content-Type的值 application/json
parser_classes = [JSONParser,]
media_type_list = ['application/json',]
如果客戶端的Content-Type的值和 application/json 匹配:JSONParser處理數(shù)據(jù)
如果客戶端的Content-Type的值和 application/x-www-form-urlencoded 匹配:FormParser處理數(shù)據(jù)
配置:
單視圖:
class UsersView(APIView):
parser_classes = [JSONParser,]
全局配置:
REST_FRAMEWORK = {
'VERSION_PARAM':'version',
'DEFAULT_VERSION':'v1',
'ALLOWED_VERSIONS':['v1','v2'],
# 'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.HostNameVersioning"
'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning",
'DEFAULT_PARSER_CLASSES':[
'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
]
}
3. 序列化 重點(diǎn)0嗬<⒙!
這 tm 是什么肥败?
- 序列化: 對(duì)象 --> 字符串趾浅,
- 反序列化: 字符串 --> 對(duì)象。
- 目前學(xué)過的:json/pickle
restful 序列化 存在的意義:
- 就是為了解決 QuerySet 的序列化問題馒稍。
models.py
from django.db import models
# Create your models here.
class Menu(models.Model):
name = models.CharField(max_length=32)
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 Role(models.Model):
name = models.CharField(max_length=32)
復(fù)雜序列化
views.py
a. 復(fù)雜序列化
解決方案一:
class MyCharField(serializers.CharField):
def to_representation(self, value):
data_list = []
for row in value:
data_list.append(row.name)
return data_list
class UsersSerializer(serializers.Serializer):
name = serializers.CharField() # obj.name
pwd = serializers.CharField() # obj.pwd
group_id = serializers.CharField() # obj.group_id
xxxx = serializers.CharField(source="group.title") # obj.group.title
x1 = serializers.CharField(source="group.mu.name") # obj.mu.name
# x2 = serializers.CharField(source="roles.all") # obj.mu.name
x2 = MyCharField(source="roles.all") # obj.mu.name
解決方案二:
class MyCharField(serializers.CharField):
def to_representation(self, value):
return {'id': value.pk, 'name': value.name}
class UsersSerializer(serializers.Serializer):
name = serializers.CharField() # obj.name
pwd = serializers.CharField() # obj.pwd
group_id = serializers.CharField() # obj.group_id
xxxx = serializers.CharField(source="group.title") # obj.group.title
x1 = serializers.CharField(source="group.mu.name") # obj.mu.name
# x2 = serializers.CharField(source="roles.all") # obj.mu.name
x2 = serializers.ListField(child=MyCharField(), source="roles.all") # obj.mu.name
這是復(fù)雜序列化的第三種方法皿哨,也是極力推薦的方法 *************
class UserSerializer(serializers.Serializer):
name = serializers.CharField() # obj.name
pwd = serializers.CharField() # obj.pwd
group_id = serializers.CharField() # obj.group_id
g_title = serializers.CharField(source='group.title') # obj.group.title
g_mu_name = serializers.CharField(source='group.mu.name') # obj.group.name
# M2M,這樣寫的話纽谒,只能拿到 對(duì)象
# roles = serializers.CharField(source='roles.all') # "roles": "<QuerySet [<Role: Role object>]>"
roles = serializers.CharField(source='roles.all') # "roles": "<QuerySet [<Role: Role object>]>"
xx = serializers.SerializerMethodField()
def get_xx(self,obj):
role_list = obj.roles.all()
data_list = []
for role_obj in role_list:
data_list.append({'pk':role_obj.pk,'name':role_obj.name,})
return data_list
不管哪種方法证膨,都走這個(gè)視圖
class UserView(APIView):
def get(self,request,*args,**kwargs):
self.dispatch
# 方式一:用我們之前最簡單粗暴的方法。
# user_list = models.UserInfo.objects.all().values('name','pwd','group_id','group__title','group__mu__name')
# return Response(user_list)
# 方式二:多對(duì)象
user_list = models.UserInfo.objects.all()
# print(user_list)
# obj = user_list.first()
# o_name = obj.roles.all()
# for i in o_name:
# print(i.name)
ser = UserSerializer(instance=user_list,many=True)
return Response(ser.data)
b. 基于 model鼓黔。 在序列化里面繼承了 ModelSerializer類
class PasswordValidator(object):
def __init__(self, base):
self.base = base
def __call__(self, value):
if value != self.base:
message = '用戶輸入的值必須是 %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.
"""
# 執(zhí)行驗(yàn)證之前調(diào)用,serializer_fields是當(dāng)前字段對(duì)象
pass
# 注意這里繼承的類:ModelSerializer
class UsersSerializer(serializers.ModelSerializer):
x = serializers.CharField(source='name')
class Meta:
model = models.UserInfo
# fields = "__all__"
fields = ['name', 'pwd', 'x', 'group'] # 自定義字段時(shí)候要注意指定 source央勒,source里面的數(shù)據(jù)必須是數(shù)據(jù)庫有的不见。
extra_kwargs = {
'name': {'min_length': 6},
'pwd': {'validators': [PasswordValidator(666), ]}}
# 使用
class UsersView(APIView):
def get(self,request,*args,**kwargs):
# self.dispatch
user_list = models.UserInfo.objects.all()
# [obj1,obj2,obj3]
# 序列化。
ser = UsersSerializer(instance=user_list,many=True,context={'request':request})
return Response(ser.data)
def post(self,request,*args,**kwargs):
# 驗(yàn)證:對(duì)請(qǐng)求發(fā)來的數(shù)據(jù)進(jìn)行驗(yàn)證崔步。
ser = UsersSerializer(data=request.data)
if ser.is_valid():
print(ser.validated_data)
else:
print(ser.errors)
return Response('...')
c. 生成 url
class Users_Serializer(serializers.ModelSerializer):
group = serializers.HyperlinkedIdentityField(view_name='detail')
class Meta:
model = models.UserInfo
fields = '__all__'
extra_kwargs = {
'user': {'min_length': 6},
'pwd': {'validators': [PasswordValidator(666),]}
}
class Users_View(APIView):
def get(self, request, *args, **kwargs):
# 序列化稳吮,將數(shù)據(jù)庫查詢字段序列化為字典
data_list = models.UserInfo.objects.all()
ser = Users_Serializer(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):
# 驗(yàn)證,對(duì)請(qǐng)求發(fā)來的數(shù)據(jù)進(jìn)行驗(yàn)證
print(request.data)
ser = Users_Serializer(data=request.data)
if ser.is_valid():
print(ser.validated_data)
else:
print(ser.errors)
return Response('POST請(qǐng)求井濒,響應(yīng)內(nèi)容')
d. 自動(dòng)生成 url 繼承該類: HyperlinkedModelSerializer
class UsersSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = models.UserInfo
fields = "__all__"
# fields = ['id','name','pwd']
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)
# 方式二之多對(duì)象
user_list = models.UserInfo.objects.all()
# [obj1,obj2,obj3]
ser = UsersSerializer(instance=user_list,many=True,context={'request':request})
return Response(ser.data)
e. 關(guān)于請(qǐng)求數(shù)據(jù)驗(yàn)證
# 第一種:
class PasswordValidator(object):
def __init__(self, base):
self.base = base
def __call__(self, value):
if value != self.base:
message = '用戶輸入的值必須是 %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.
"""
# 執(zhí)行驗(yàn)證之前調(diào)用,serializer_fields是當(dāng)前字段對(duì)象
pass
class UsersSerializer(serializers.Serializer):
name = serializers.CharField(min_length=6)
pwd = serializers.CharField(error_messages={'required': '密碼不能為空'}, validators=[PasswordValidator('666')])
# 第二種
class PasswordValidator(object):
def __init__(self, base):
self.base = base
def __call__(self, value):
if value != self.base:
message = '用戶輸入的值必須是 %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.
"""
# 執(zhí)行驗(yàn)證之前調(diào)用,serializer_fields是當(dāng)前字段對(duì)象
pass
class UsersSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "__all__"
extra_kwargs = {
'name': {'min_length': 6},
'pwd': {'validators': [PasswordValidator(666), ]}
}
使用:
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)
# 方式二之多對(duì)象
user_list = models.UserInfo.objects.all()
# [obj1,obj2,obj3]
ser = UsersSerializer(instance=user_list, many=True, context={'request': request})
return Response(ser.data)
def post(self, request, *args, **kwargs):
ser = UsersSerializer(data=request.data)
if ser.is_valid():
print(ser.validated_data)
else:
print(ser.errors)
return Response('...')