假如把drf看做一個漢堡包,我們之前講的模塊屬於漢堡包前面的蓋蓋(請求模塊、渲染模塊)和底底(異常模塊、解析模塊、響應模塊),但是真正中間的夾心沒有講,那么今天我就和大家來看一下漢堡包的夾心(序列化及反序列化)到底是什么東西。
drf序列化(Serializer)
什么是drf序列化?序列化就是將Model對象序列化成字符串用戶傳輸
序列化使用
數據准備
models.py
class User(models.Model):
SEX_CHOICES = [
[0, '男'],
[1, '女'],
]
name = models.CharField(max_length=64)
pwd = models.CharField(max_length=32)
phone = models.CharField(max_length=11, null=True, default=None)
sex = models.IntegerField(choices=SEX_CHOICES, default=0)
icon = models.ImageField(upload_to='icon', default='icon/default.jpg')
class Meta:
# 自定義創建的表名
db_table = 'user'
# admin界面中顯示的表名與表名復數形式
verbose_name = '用戶' #復數形式
verbose_name_plural = verbose_name #非復數形式
def __str__(self):
return self.name
配置層: settings.py
# 注冊rest_framework
INSTALLED_APPS = [
# ...
'rest_framework',
]
# 配置數據庫
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'db',
'USER': 'root',
'PASSWORD': 'root'
}
}
# media資源
MEDIA_URL = '/media/' # 后期高級序列化類與視圖類,會使用該配置
MEDIA_ROOT = os.path.join(BASE_DIR, 'media') # media資源路徑
# 國際化配置
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_L10N = True
USE_TZ = False
- 主路由:
from django.conf.urls import url, include
from django.contrib import admin
from django.views.static import serve
from django.conf import settings
urlpatterns = [
url(r'^admin/', admin.site.urls),
# 路由分發
url(r'^api/', include('api.urls')),
# 暴露靜態文件
url('^media/(?P<path>.*)', serve, {'document_root':settings.MEDIA_ROOT})
]
- 子路由:
urlpatterns = [
url(r'^users/$', views.User.as_view()),
url(r'^users/(?P<pk>.*)/$', views.User.as_view()),
]
序列化使用
注意:
- 序列化提供給前台的字段個數由后台決定,可以少提供,
- 但是提供的數據庫對應的字段,名字一定要與數據庫字段相同
- 設置方法字段,字段名可以隨意,字段值有 get_字段名 提供,來完成一些需要處理在返回的數據
- 序列化組件 - 為每一個model類通過一套序列化工具類
- 序列化組件的工作方式與django froms組件非常相似
- 序列化層:api/serializers.py
"""
1)設置需要返回給前台 那些model類有對應的 字段,不需要返回的就不用設置了
2)設置方法字段,字段名可以隨意,字段值有 get_字段名 提供,來完成一些需要處理在返回的數據
"""
# 序列化組件 - 為每一個model類通過一套序列化工具類
# 序列化組件的工作方式與django froms組件非常相似
from rest_framework import serializers, exceptions
from django.conf import settings
from . import models
class UserSerializer(serializers.Serializer):
name = serializers.CharField()
phone = serializers.CharField()
# 序列化提供給前台的字段個數由后台決定,可以少提供,
# 但是提供的數據庫對應的字段,名字一定要與數據庫字段相同
# sex = serializers.IntegerField()
# icon = serializers.ImageField()
# 自定義序列化屬性
# 屬性名隨意,值由固定的命名規范方法提供:
# get_屬性名(self, 參與序列化的model對象)
# 返回值就是自定義序列化屬性的值
gender = serializers.SerializerMethodField()
def get_gender(self, obj):
# choice類型的解釋型值 get_字段_display() 來訪問
return obj.get_sex_display()
icon = serializers.SerializerMethodField()
def get_icon(self, obj):
# settings.MEDIA_URL: 自己配置的 /media/,給后面高級序列化與視圖類准備的
# obj.icon不能直接作為數據返回,因為內容雖然是字符串,但是類型是ImageFieldFile類型
return '%s%s%s' % (r'http://127.0.0.1:8000', settings.MEDIA_URL, str(obj.icon))
- 視圖層
"""
1)從數據庫中將要序列化給前台的model對象,或是對個model對象查詢出來
user_obj = models.User.objects.get(pk=pk) 或者
user_obj_list = models.User.objects.all()
2)將對象交給序列化處理,產生序列化對象,如果序列化的是多個數據,要設置many=True
user_ser = serializers.UserSerializer(user_obj) 或者
user_ser = serializers.UserSerializer(user_obj_list, many=True)
#many會遍歷user_obj_list,觸發是一個具體對象
3)序列化 對象.data 就是可以返回給前台的序列化數據
return Response({
'status': 0,
'msg': 0,
'results': user_ser.data
})
"""
class User(APIView):
def get(self, request, *args, **kwargs):
pk = kwargs.get('pk')
if pk:
try:
# 用戶對象不能直接作為數據返回給前台
user_obj = models.User.objects.get(pk=pk)
# 序列化一下用戶對象
user_ser = serializers.UserSerializer(user_obj)
# print(user_ser, type(user_ser))
return Response({
'status': 0,
'msg': 0,
'results': user_ser.data
#看源碼:data=empty 是參與反序列化的數據
})
except:
return Response({
'status': 2,
'msg': '用戶不存在',
})
else:
# 用戶對象列表(queryset)不能直接作為數據返回給前台
user_obj_list = models.User.objects.all()
# 序列化一下用戶對象
user_ser_data = serializers.UserSerializer(user_obj_list, many=True).data
return Response({
'status': 0,
'msg': 0,
'results': user_ser_data
})
反序列化使用
什么是drf的反序列化?emmm,丫就是將字符串反序列化成Model對象用於使用
- 反序列層:api/serializers.py
"""
1)設置必填與選填序列化字段,設置校驗規則
2)為需要額外校驗的字段提供局部鈎子函數,如果該字段不入庫,且不參與全局鈎子校驗,可以將值取出校驗
3)為有聯合關系的字段們提供全局鈎子函數,如果某些字段不入庫,可以將值取出校驗
4)重寫create方法,完成校驗通過的數據入庫工作,得到新增的對象
"""
from rest_framework import serializers, exceptions
from django.conf import settings
from . import models
class UserDeserializer(serializers.Serializer):
# 1) 哪些字段必須反序列化 :入庫的字段都需要反序列化
# 2) 字段都有哪些安全校驗 :比如字段長度啊,什么的
# 3) 哪些字段需要額外提供校驗 :name或者password
# 4) 哪些字段間存在聯合校驗 :需要用到全局鈎子的字段哈哈哈
# 注:反序列化字段都是用來入庫的,不會出現自定義方法屬性,會出現可以設置校驗規則的自定義屬性(re_pwd)
name = serializers.CharField(
max_length=64,
min_length=3,
error_messages={
'max_length': '太長',
'min_length': '太短'
}
)
pwd = serializers.CharField()
phone = serializers.CharField(required=False)
sex = serializers.IntegerField(required=False)
# 自定義有校驗規則的反序列化字段
re_pwd = serializers.CharField(required=True)
# 小結:
# name,pwd,re_pwd為必填字段
# phone,sex為選填字段
# 五個字段都必須提供完成的校驗規則
# 局部鈎子:validate_要校驗的字段名(self, 當前要校驗字段的值)
# 校驗規則:校驗通過返回原值,校驗失敗,拋出異常
def validate_name(self, value):
if 'g' in value.lower(): # 名字中不能出現g
raise exceptions.ValidationError('名字非法!')
return value
# 全局鈎子:validate(self, 系統與局部鈎子校驗通過的所有數據)
# 校驗規則:校驗通過返回原值,校驗失敗,拋出異常
def validate(self, attrs):
pwd = attrs.get('pwd')
re_pwd = attrs.pop('re_pwd')
if pwd != re_pwd:
raise exceptions.ValidationError({'pwd&re_pwd': '兩次密碼不一致'})
return attrs
# 要完成新增,需要自己重寫 create 方法
def create(self, validated_data):
# 盡量在所有校驗規則完畢之后,數據可以直接入庫
return models.User.objects.create(**validated_data)
- 視圖層
"""
1)book_ser = serializers.UserDeserializer(data=request_data) # 數據必須賦值data
2)book_ser.is_valid() # 結果為 通過 | 不通過
3)不通過返回 book_ser.errors 給前台,通過 book_ser.save() 得到新增的對象,再正常返回
"""
class User(APIView):
# 只考慮單增
def post(self, request, *args, **kwargs):
# 請求數據
request_data = request.data
# 數據是否合法(增加對象需要一個字典數據)
if not isinstance(request_data, dict) or request_data == {}:
return Response({
'status': 1,
'msg': '數據有誤',
})
# 數據類型合法,但數據內容不一定合法,需要校驗數據,校驗(參與反序列化)的數據需要賦值給data
book_ser = serializers.UserDeserializer(data=request_data)
# 序列化對象調用is_valid()完成校驗,校驗失敗的失敗信息都會被存儲在 序列化對象.errors
if book_ser.is_valid():
# 校驗通過,完成新增
book_obj = book_ser.save()
return Response({
'status': 0,
'msg': 'ok',
'results': serializers.UserSerializer(book_obj).data
})
else:
# 校驗失敗
return Response({
'status': 1,
'msg': book_ser.errors, #所有錯誤的信心都會藏在book_ser.errors中
#將錯誤字段的信息返回給前台
})
反序列化總結
視圖層:
- 要把校驗的數據給(data= request.data)
- .is_valid:結果為通過/不通過
- .save():不通過返回.errors給前台,通過save()得到新增的對象,再正常返回。
反序列層:
- 設置必填與選填序列化字段,設置校驗規則
- 為需要額外校驗的字段提供局部鈎子函數,如果該字段不入庫,且不參與全局鈎子校驗,可以將值取出校驗
- 為有聯合關系的字段們提供全局鈎子函數,如果某些字段不入庫,可以將值取出校驗
- 重寫create方法,完成校驗通過的數據入庫工作,得到新增的對象