Json序列化與Serializer序列化的區別
Json:
序列化: 將對象序列化成字符串用於傳輸
反序列化: 將字符串反序列化成對象用於使用
Serializer:
序列化: 將Model類對象序列化成字符串用於傳輸
反序列化: 將字符串反序列化成Model對象用於使用
Serializer
序列化組件的工作方式與django froms組件非常相似,爲每一個model類通過一套序列化工具類
Serializer的構造方法爲:
Serializer(instance=None, data=empty, **kwarg)
- 用於序列化時,將模型類對象傳入instance參數
- 用於反序列化時,將要被反序列化的數據傳入data參數
- 除了instance和data參數外,在構造Serializer對象時,還可通過context參數額外添加數據,如
serializer = AccountSerializer(account, context={'request': request})
通過context參數附加的數據,可以通過Serializer對象的context屬性獲取。
注意:
- 使用序列化器的時候一定要注意,序列化器聲明瞭以後,不會自動執行,需要我們在視圖中進行調用纔可以。
- 序列化器無法直接接收數據,需要我們在視圖中創建序列化器對象時把使用的數據傳遞過來。
- 序列化器的字段聲明類似於我們前面使用過的表單系統。
- 開發restful api時,序列化器會幫我們把模型數據轉換成字典.
- drf提供的視圖會幫我們把字典轉換成json,或者把客戶端發送過來的數據轉換字典.
使用
序列化器的使用分兩個階段:
在客戶端請求時,使用序列化器可以完成對數據的反序列化。
在服務器響應時,使用序列化器可以完成對數據的序列化。
- 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()),
]
Serializer 序列化的使用
序列化提供給前臺的字段個數由後臺決定,可以少提供
但是要提供與數據庫對應的字段,名字一定要與數據庫字段相同
可自定義序列化字段,字段名可以隨意,但要定義 def get_字段名(self, obj) 函數,來完成一些需要處理在返回的數據
- 應用下創建serializers.py
from rest_framework import serializers, exceptions
from django.conf import settings
from . import models
class UserSerializer(serializers.Serializer):
# 定義需要序列化的字段 名字一定要與數據庫字段相同
name = serializers.CharField()
phone = serializers.CharField()
# 自定義序列化字段
# 屬性名隨意,值由固定的命名規範方法提供:
# get_屬性名(self, 參與序列化的model對象)
# 返回值就是自定義序列化屬性的值
gender = serializers.SerializerMethodField()
def get_gender(self, obj): # 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))
- views.py
1)從數據庫中將要序列化給前臺的model對象,或是多個model對象查詢出來
user_obj = models.User.objects.get(pk=pk)
# 或者
user_obj_list = models.User.objects.all() # 得到的是查詢集QuerySet
2)將對象交給序列化處理,產生序列化對象,如果序列化的是多個數據(查詢集QuerySet),要設置many=True
user_ser = serializers.UserSerializer(user_obj) 或者
user_ser = serializers.UserSerializer(user_obj_list, many=True)
# 注意: many會遍歷user_obj_list,觸發是一個具體對象,否則就需要制定many=True
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)
# print(user_ser.data) # {'name': 'xiongda', 'phone': '110'} 序列化後的字段
return Response({
'status': 0,
'msg': 0,
'results': user_ser.data
})
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
})
Serializer 反序列化的使用
使用序列化器進行反序列化時,需要對數據進行驗證後,才能獲取驗證成功的數據
在定義序列化器時,指明每個字段的序列化類型和選項參數,本身就是一種驗證行爲。
1)設置必填與選填序列化字段,設置校驗規則
2)爲需要額外校驗的字段提供局部鉤子函數,如果該字段不入庫,且不參與全局鉤子校驗,可以將值取出校驗
3)爲有聯合關係的字段們提供全局鉤子函數,如果某些字段不入庫,可以將值取出校驗
4)重寫create方法,完成校驗通過的數據入庫工作,得到新增的對象
- serializers.py
# 1) 哪些字段必須反序列化
# 2) 字段都有哪些安全校驗
# 3) 哪些字段需要額外提供校驗
# 4) 哪些字段間存在聯合校驗
# 注:反序列化字段都是用來入庫的,不會出現自定義方法屬性,會出現可以設置校驗規則的自定義屬性(如:re_pwd)
class UserDeserializer(serializers.Serializer):
name = serializers.CharField(
max_length=64,
min_length=3,
error_messages={
'max_length': '太長',
'min_length': '太短'
}
)
pwd = serializers.CharField()
phone = serializers.CharField(required=False) # 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):
print(value) # name字段的值
if 'g' in value.lower(): # 名字中不能出現g
raise exceptions.ValidationError('名字非法,是個雞賊!')
return value
# 全局鉤子:validate(self, 系統與局部鉤子校驗通過的所有數據)
# 校驗規則:校驗通過返回原值,校驗失敗,拋出異常
def validate(self, attrs):
print(attrs) # OrderedDict([('name', 'haha'), ('pwd', '123'), ('phone', '120'), ('re_pwd', '123')]) 可以當做是字典
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):
print(validated_data) # {'name': 'haha', 'pwd': '123', 'phone': '120'}
# 儘量在所有校驗規則完畢之後,數據可以直接入庫
return models.User.objects.create(**validated_data)
- views.py
1) 前端傳來的數據字段必須賦值給系列化器的data參數
book_ser = serializers.UserDeserializer(data=request_data)
2) 在獲取反序列化的數據前,必須調用is_valid()方法進行驗證,驗證成功返回True,否則返回False。
book_ser.is_valid() # 結果爲 通過(True) | 不通過(Fales)
若檢驗不通過,可以通過序列化器對象的errors屬性獲取錯誤信息,返回字典,包含了字段和字段的錯誤
book_ser.errors
若校驗通過,可以通過序列化器對象的validated_data屬性獲取數據。
book_ser.calidated_data
3) 得到新增的對象,再正常返回
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() # 自動調用系列化器裏的create方法,並拿到新增的對象
return Response({
'status': 0,
'msg': 'ok',
'results': serializers.UserSerializer(book_obj).data # 拿到序列化數據給前臺
})
else:
# 校驗失敗
return Response({
'status': 1,
'msg': book_ser.errors, # 將錯誤字段的信息返回給前臺
})
反序列化-保存數據
前面的驗證數據成功後,我們可以使用序列化器來完成數據反序列化的過程.這個過程可以把數據轉成模型類對象.
可以通過實現create()和update()兩個方法來實現。
class UserDeserializer(serializers.Serializer):
...
def create(self, validated_data): # 新增
return models.User.objects.create(**validated_data)
def update(self, instance, validated_data): # 更新
# instance爲要更新的對象實例
instance.name = validated_data.get('name', instance.name)
instance.pwd= validated_data.get('pwd', instance.pwd)
instance.save()
return instance
實現了上述兩個方法後,在反序列化數據的時候,就可以通過save()方法返回一個數據對象實例了
book = serializer.save()
如果創建序列化器對象的時候,沒有傳遞instance實例,則調用save()方法的時候,create()被調用,相反,如果傳遞了instance實例,則調用save()方法的時候,update()被調用。
from db.serializers import BookInfoSerializer
data = {'btitle': '封神演義'}
serializer = BookInfoSerializer(data=data)
serializer.is_valid() # True
serializer.save() # <BookInfo: 封神演義>
from db.models import BookInfo
book = BookInfo.objects.get(id=2)
data = {'btitle': '倚天劍'}
serializer = BookInfoSerializer(book, data=data)
serializer.is_valid() # True
serializer.save() # <BookInfo: 倚天劍>
book.btitle # '倚天劍'
附加說明
1) 在對序列化器進行save()保存時,可以額外傳遞數據,這些數據可以在create()和update()中的validated_data參數獲取到
# request.user 是django中記錄當前登錄用戶的模型對象
serializer.save(xionger=request.user)
2)默認序列化器必須傳遞所有required的字段,否則會拋出驗證異常。但是我們可以使用partial參數來允許部分字段更新
# Update `comment` with partial data
serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)
補充
常用字段類型:
字段 | 字段構造方式 |
---|---|
BooleanField | BooleanField() |
NullBooleanField | NullBooleanField() |
CharField | CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True) |
EmailField | EmailField(max_length=None, min_length=None, allow_blank=False) |
RegexField | RegexField(regex, max_length=None, min_length=None, allow_blank=False) |
SlugField | SlugField(max_length=50, min_length=None, allow_blank=False) 正則字段,驗證正則模式 [a-zA-Z0-9*-]+ |
URLField | URLField(max_length=200, min_length=None, allow_blank=False) |
UUIDField | UUIDField(format='hex_verbose') format: 1) 'hex_verbose' 如"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex' 如 "5ce0e9a55ffa654bcee01238041fb31a" 3)'int' - 如: "123456789012312313134124512351145145114" 4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a" |
IPAddressField | IPAddressField(protocol='both', unpack_ipv4=False, **options) |
IntegerField | IntegerField(max_value=None, min_value=None) |
FloatField | FloatField(max_value=None, min_value=None) |
DecimalField | DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位數 decimal_palces: 小數點位置 |
DateTimeField | DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None) |
DateField | DateField(format=api_settings.DATE_FORMAT, input_formats=None) |
TimeField | TimeField(format=api_settings.TIME_FORMAT, input_formats=None) |
DurationField | DurationField() |
ChoiceField | ChoiceField(choices) choices與Django的用法相同 |
MultipleChoiceField | MultipleChoiceField(choices) |
FileField | FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
ImageField | ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
ListField | ListField(child=, min_length=None, max_length=None) |
DictField | DictField(child=) |
選項參數:
參數名稱 | 作用 |
---|---|
max_length | 最大長度 |
min_lenght | 最小長度 |
allow_blank | 是否允許爲空 |
trim_whitespace | 是否截斷空白字符 |
max_value | 最小值 |
min_value | 最大值 |
通用參數:
參數名稱 | 說明 |
---|---|
read_only | 表明該字段僅用於序列化輸出,默認False |
write_only | 表明該字段僅用於反序列化輸入,默認False |
required | 表明該字段在反序列化時必須輸入,默認True |
default | 反序列化時使用的默認值 |
allow_null | 表明該字段是否允許傳入None,默認False |
validators | 該字段使用的驗證器 |
error_messages | 包含錯誤編號與錯誤信息的字典 |
label | 用於HTML展示API頁面時,顯示的字段名稱 |
help_text | 用於HTML展示API頁面時,顯示的字段幫助提示信息 |