Django序列化組件Serializers使用詳解
本文主要系統(tǒng)性的講解django rest framwork 序列化組件的使用,基本看完可以解決工作中序列化90%的問題,寫作參考官方文檔https://www.django-rest-framework.org/api-guide/serializers/#modelserializer,分成如下九個(gè)部分:
01、為什么要用序列化組件
我們知道前后端常用json數(shù)據(jù)結(jié)構(gòu)交互, 在后端我們常想把一個(gè)對(duì)象返回給前端,但是json序列化是不能序列化對(duì)象(不過可以添加序列化參數(shù)encoder序列化原理和序列化組件差不多需要自己定義序列化類和返回的結(jié)構(gòu)),所以就有了我們的序列化組件,可以自定義特定結(jié)構(gòu)把對(duì)象序列化返回給前端,同時(shí)可以對(duì)前端傳入的參數(shù)進(jìn)行數(shù)據(jù)校驗(yàn)等功能。
02、序列化組件的基本使用
models
from django.db import models # Create your models here. class Book(models.Model): id = models.IntegerField(primary_key=True) title = models.CharField(max_length=255) desc = models.CharField(max_length=255) is_deleted = models.IntegerField(choices=[(1, "刪除"), (0, "未刪除")]) author = models.CharField(max_length=255)
serializer
from rest_framework.serializers import Serializer from rest_framework import serializers class BookSerializer(Serializer): id = serializers.IntegerField() title = serializers.CharField() desc = serializers.CharField() is_deleted = serializers.ChoiceField(choices=[(1, "刪除"), (0, "未刪除")], source="get_is_deleted_display") author = serializers.CharField()
views
from app01.models import Book from app01.serializer import BookSerializer from django.http import HttpResponse, JsonResponse # Create your views here. def get_books(request): books = Book.objects.all() se = BookSerializer(books, many=True) return JsonResponse(se.data, safe=False)
結(jié)果返回:
[{"id": 1, "title": "活著", "desc": "講述一代人的人生", "is_deleted": "未刪除", "author": "余華"}]
在寫法上model和serializer的寫法非常相近,但內(nèi)在邏輯model是與數(shù)據(jù)庫(kù)表的關(guān)系映射,serializer是對(duì)對(duì)象的序列化和反序列化。
03、序列化組件常用字段
常用字段類型
| 字段 | 字段構(gòu)造方式 |
|---|---|
| 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(maxlength=50, min_length=None, allow_blank=False) 正則字段,驗(yàn)證正則模式 [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: 最多位數(shù) decimal_palces: 小數(shù)點(diǎn)位置 |
| 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=) |
選項(xiàng)參數(shù):
| 名稱 | 作用 |
|---|---|
| max_length | 最大長(zhǎng)度 |
| min_lenght | 最小長(zhǎng)度 |
| allow_blank | 是否允許為空 |
| trim_whitespace | 是否截?cái)嗫瞻鬃址?/td> |
| max_value | 最大值 |
| min_value | 最小值 |
通用參數(shù)
| 參數(shù)名稱 | 說明 |
|---|---|
| read_only | 表明該字段僅用于序列化輸出,默認(rèn)False |
| write_only | 表明該字段僅用于反序列化輸入,默認(rèn)False |
| required | 表明該字段在反序列化時(shí)必須輸入,默認(rèn)True |
| default | 反序列化時(shí)使用的默認(rèn)值 |
| allow_null | 表明該字段是否允許傳入None,默認(rèn)False |
| validators | 該字段使用的驗(yàn)證器 |
| error_messages | 包含錯(cuò)誤編號(hào)與錯(cuò)誤信息的字典 |
| label | 用于HTML展示API頁(yè)面時(shí),顯示的字段名稱 |
| help_text | 用于HTML展示API頁(yè)面時(shí),顯示的字段幫助提示信息 |
在這里額外講一個(gè)參數(shù)source,在官方文檔中是這樣解釋的:
將用于填充字段的屬性的名稱??梢允莾H接受self參數(shù)的方法,例如URLField(source='get_absolute_url'),也可以使用點(diǎn)分符號(hào)遍歷屬性,例如EmailField(source='user.email')。當(dāng)使用點(diǎn)分符號(hào)序列化字段時(shí),default如果在屬性遍歷期間任何對(duì)象不存在或?yàn)榭?,則可能需要提供一個(gè)值。
該值source='*'具有特殊含義,用于指示應(yīng)將整個(gè)對(duì)象傳遞給該字段。這對(duì)于創(chuàng)建嵌套表示或?qū)π枰L問完整對(duì)象才能確定輸出表示的字段很有用。
默認(rèn)為字段名稱。
其中比較常用的用法:
1、source="get_field_name_display"如上所展示,在choice字段中可以展示選項(xiàng)對(duì)應(yīng)的解釋,這中用法代表的是官方解釋說的可以是僅接受self參數(shù)的方法,也就是source中可以填serializer對(duì)象可以調(diào)用的方法(方法中需要傳入self),內(nèi)在邏輯是這個(gè)字段會(huì)展示此方法的返回的結(jié)果。
2、source='user.email'這種用法常在ModelSerializer的子類中,其中user為User對(duì)象,此中寫法是指展示user的email屬性,常用于我們想把外鍵對(duì)象user的屬性和本對(duì)象的屬性展示在同一層級(jí),而不是下一級(jí)。
04、序列化組件is_valid、validated_data
當(dāng)我們定義好序列化器時(shí),怎么校驗(yàn)傳入的字段呢?那就是is_valid方法,可以根據(jù)定義序列化器的校驗(yàn)規(guī)則判斷傳入字段是否合法。
serializer = CommentSerializer(data={'email': 'foobar', 'content': 'baz'})
serializer.is_valid()
# False
serializer.errors
# {'email': ['Enter a valid e-mail address.'], 'created': ['This field is required.']}
然后serializer.validated_data就可以獲取校驗(yàn)過后的數(shù)據(jù)字典。
05、序列化組件校驗(yàn)字段
序列化組件校驗(yàn)字段的方式常有三種:
1、首先是在字段的validators屬性, 其中傳入一個(gè)校驗(yàn)方法列表如:validators=(my_validator, )其中my_validator中定義校驗(yàn)規(guī)則。
def multiple_of_ten(value):
if value % 10 != 0:
raise serializers.ValidationError('Not a multiple of ten')
class GameRecord(serializers.Serializer):
score = IntegerField(validators=[multiple_of_ten])
2、最常用的是定義一個(gè)validate_field_name(self, value)的函數(shù)(其中field_name指的是字段名),函數(shù)內(nèi)是具體的邏輯。
from rest_framework import serializers
class BlogPostSerializer(serializers.Serializer):
title = serializers.CharField(max_length=100)
content = serializers.CharField()
def validate_title(self, value):
"""
Check that the blog post is about Django.
"""
if 'django' not in value.lower():
raise serializers.ValidationError("Blog post is not about Django")
return value
3、最后一種是定義一個(gè)validate(self, data)其中data是所有字段的鍵值對(duì),所以這個(gè)校驗(yàn)方法是對(duì)象級(jí)別的校驗(yàn)。
from rest_framework import serializers
class EventSerializer(serializers.Serializer):
description = serializers.CharField(max_length=100)
start = serializers.DateTimeField()
finish = serializers.DateTimeField()
def validate(self, data):
"""
Check that start is before finish.
"""
if data['start'] > data['finish']:
raise serializers.ValidationError("finish must occur after start")
return data
當(dāng)然或許當(dāng)你看到這里會(huì)問why?how? 只能說源碼是最好的答案。
06、序列化組件.create() and .update()
在我們定義的序列化類中, 可以添加create和update方法,當(dāng)我們有需求是根據(jù)反序列化后的數(shù)據(jù)在數(shù)據(jù)庫(kù)表中創(chuàng)建記錄或者更新某條數(shù)據(jù),這時(shí)我們就可以在create方法和update方法中定義對(duì)應(yīng)的邏輯。
class CommentSerializer(serializers.Serializer):
email = serializers.EmailField()
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
def create(self, validated_data):
return Comment.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.email = validated_data.get('email', instance.email)
instance.content = validated_data.get('content', instance.content)
instance.created = validated_data.get('created', instance.created)
instance.save()
return instance
接下來調(diào)用serializer.save()命令便可創(chuàng)建一條紀(jì)錄或者更新一條記錄,其中判斷save時(shí)什么時(shí)候是創(chuàng)建什么時(shí)候是更新呢?關(guān)鍵在于serializer的實(shí)例化。
# .save() will create a new instance. serializer = CommentSerializer(data=data) serializer.save() # .save() will update the existing `comment` instance. serializer = CommentSerializer(comment, data=data) serializer.save()
其中當(dāng)Serializer類實(shí)例化沒有傳入model對(duì)象時(shí)會(huì)調(diào)用create方法創(chuàng)建一條記錄, 如果Serializer類實(shí)例化時(shí)傳入了model對(duì)象就會(huì)調(diào)用update方法更新一條記錄。
有時(shí)除了反序列化的字段我們還需要其他字段怎么辦呢?我們可以在save中傳入?yún)?shù)名和值,可以在validated_data中根據(jù)參數(shù)名取到對(duì)應(yīng)的值。
serializer.save(owner=request.user)
這樣我們就可以在validated_data.get("owner")就可以取到user對(duì)象了。
07、序列化組件ModelSerializer
ModelSerializer和表單的ModelForm組件很相似,都極大簡(jiǎn)化了我們的開發(fā),可以在內(nèi)部類Meta中定義對(duì)應(yīng)的model,ModelSerializer就會(huì)自動(dòng)生成model字段對(duì)應(yīng)的Field不用我們定義。
class AccountSerializer(serializers.ModelSerializer): class Meta: model = Account fields = ['id', 'account_name', 'users', 'created']
其中fields中定義序列化的字段,如果是全部字段就寫__all__, 上述例子我們沒有定義具體的字段,ModelSerializer幫我們自動(dòng)生成了 'id', 'account_name', 'users', 'created'的Field。
08、序列化組件構(gòu)造復(fù)雜的結(jié)構(gòu)
以下是個(gè)存在一對(duì)多和多對(duì)多字段的序列化器
serializer
from res_framework import serializers
#這個(gè)類用于被實(shí)例化,多對(duì)多字段這么寫
class AuthorSerializer(serializers.Serializer):
id = serializers.Charfield()
name = serializers.Charfield()
age = serializers.Charfield()
#傳給views.py的主類
class BookSerializer(serializers.Serializer):
name = serializers.Charfield()
#source 可以指定字段 , id是要序列化的表名。
id = serializers.CharField(source='nid')
#,source后字段用.的方式可以跨表查詢。
publish = serializer.CharField(source='publish.email')
'''
如果在models.py的book類中定義一個(gè)test方法。
def test(self):
return str(self.price)+self.name
'''
# 返回的結(jié)果就會(huì)有xx字段,souce不但可以指定表模型字段,還可以指定模型表方法,并且賦值給xx變量
xx = serializers.Charfield(source='test')
#外鍵的實(shí)現(xiàn)方法:
#一對(duì)多字段
#如果要通過外鍵字段返回出版社的所有信息,包括id,name,email...
#obj是當(dāng)前循環(huán)序列化到的數(shù)據(jù)對(duì)象
publish = serializers.SerializerMethodField()
def get_publish(self,obj):
return {'id‘:obj.publish.pk,'name':obj.publish.name}
#多對(duì)多字段
#所有作者的詳情,也展示出來
authors = serializers.SerializermethodFiled()
def get_authors(self,obj):
author_list = obj.authors.all()
author_ser = AuthorSerializer(author_list,many=True)
return author_ser.data
views
from rest_framework.views import APIView
from rest_framework.response import Response
from app01 import models
class BookView(APIview):
def get(self,request,*args,**kwargs):
#獲取所有圖書數(shù)據(jù)
response = {'status':100,'msg':'獲取成功'}
book_list = models.Book.objects.all()
#實(shí)例化BookSerializer類,把要序列化的數(shù)據(jù)book_list傳入
#如果要序列化querySet對(duì)象,一定要加many = True
book_ser = BookSerializer(book_list,many=True)
#把序列化后的數(shù)據(jù)book_ser.data 拿出來放到response字典中返回給客戶端
response['data'] = book_ser.data
return Response(response)
如果使用ModelSerializer:
serializer
from app01 import models
class PublishSerializer(serializers.ModelSerializer):
class Meta: #固定寫法
# 指定要序列化Book表
model = models.Book
#指定要序列化的字段
fields = ['nid','name']
#序列化所有字段
fileds ='__all__‘
#要排除的字段(不能與fileds連用)
# exclude = ['name','price']
#深度判定
depth = 1
#如果要不按照父類的來,想要自己定義顯示的字段的話,自己定義一個(gè),覆蓋掉父類的字段屬性。
publish = serializers.SerializerMethodField() #一對(duì)多字段
def get_publish(self,obj):
return {'id‘:obj.publish.pk,'name':obj.publish.name}
這里額外解釋一下depth這個(gè)參數(shù):在對(duì)象外鍵另一對(duì)象,另一對(duì)象又外鍵另一對(duì)象以此類推,depth的作用就是可以決定序列化時(shí)的外鍵深度。
復(fù)雜序列化器的要點(diǎn)在于,serializers.SerializerMethodField()和get_field_name的使用獲取自己想得到的字段值,還有source的使用,上面有講。
09、序列化組件修改返回值to_representation、to_internal_value
to_representation(self, instance):如果序列化器定義了此方法,可以改變序列化對(duì)象data的值,也就是serializer.data的值,你可以根據(jù)自己的業(yè)務(wù)場(chǎng)景去重新構(gòu)造返回值。
def to_representation(self, instance): """Convert `username` to lowercase.""" ret = super().to_representation(instance) ret['username'] = ret['username'].lower() return ret
to_internal_value(self, data): data為未經(jīng)校驗(yàn)的數(shù)據(jù)字段, 此方法可以實(shí)現(xiàn)校驗(yàn)和修改反序列化后的值,然后返回。如果不想修改反序列化后的值只是做校驗(yàn)的話,完全可以使用validate方法替代。
def to_internal_value(self, value): if value == None: return 0 return value
總而言之,這兩個(gè)方法一個(gè)是用于重新構(gòu)造validated_data并返回,一個(gè)用于重新構(gòu)造serializer.data的值并返回。
到此這篇關(guān)于Django序列化組件Serializers使用詳解的文章就介紹到這了,更多相關(guān)Django序列化組件Serializers內(nèi)容請(qǐng)搜索本站以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持本站!
版權(quán)聲明:本站文章來源標(biāo)注為YINGSOO的內(nèi)容版權(quán)均為本站所有,歡迎引用、轉(zhuǎn)載,請(qǐng)保持原文完整并注明來源及原文鏈接。禁止復(fù)制或仿造本網(wǎng)站,禁止在非maisonbaluchon.cn所屬的服務(wù)器上建立鏡像,否則將依法追究法律責(zé)任。本站部分內(nèi)容來源于網(wǎng)友推薦、互聯(lián)網(wǎng)收集整理而來,僅供學(xué)習(xí)參考,不代表本站立場(chǎng),如有內(nèi)容涉嫌侵權(quán),請(qǐng)聯(lián)系alex-e#qq.com處理。
關(guān)注官方微信