定義Serializer數據庫
Django REST framework中的Serializer使用類來定義,須繼承自rest_framework.serializers.Serializer。 api
例如,咱們已有了一個數據庫模型類BookInfo服務器
class BookInfo(models.Model):
btitle = models.CharField(max_length=20, verbose_name='名稱')
bpub_date = models.DateField(verbose_name='發佈日期', null=True)
bread = models.IntegerField(default=0, verbose_name='閱讀量')
bcomment = models.IntegerField(default=0, verbose_name='評論量')
image = models.ImageField(upload_to='booktest', verbose_name='圖片', null=True)
咱們想爲這個模型類提供一個序列化器,能夠定義以下:post
class BookInfoSerializer(serializers.Serializer):
"""圖書數據序列化器"""
id = serializers.IntegerField(label='ID', read_only=True)
btitle = serializers.CharField(label='名稱', max_length=20)
bpub_date = serializers.DateField(label='發佈日期', required=False)
bread = serializers.IntegerField(label='閱讀量', required=False)
bcomment = serializers.IntegerField(label='評論量', required=False)
image = serializers.ImageField(label='圖片', required=False)
注意:serializer不是隻能爲數據庫模型類定義,也能夠爲非數據庫模型類的數據定義。serializer是獨立於數據庫以外的存在。測試
經常使用字段類型:ui
read_only:True表示不容許用戶本身上傳,只能用於api的輸出。若是某個字段設置了read_only=True,那麼就不須要進行數據驗證,只會在返回時,將這個字段序列化後返回url
write_only:與read_only對應;就是用戶post過來的數據,後臺服務器處理後不會再通過序列化後返回給客戶端;最多見的就是咱們在使用手機註冊的驗證碼和填寫的密碼。spa
Serializer的構造方法爲:3d
Serializer(instance=None, data=empty, **kwarg)
說明: rest
1)用於序列化時,將模型類對象傳入instance參數
2)用於反序列化時,將要被反序列化的數據傳入data參數
3)除了instance和data參數外,在構造Serializer對象時,還可經過context參數額外添加數據,如
serializer = AccountSerializer(account, context={'request': request})
經過context參數附加的數據,能夠經過Serializer對象的context屬性獲取。
Serializer使用
views
def test(request): return HttpResponse('ok')
urls
urlpatterns = [ url(r'^test/$', views.test) ]
def test(request): book = BookInfo.objects.get(id=5) # 先查詢出一個圖書對象 serializer = BookInfoSerializer(book) # 構建序列化 print(serializer.data) # 獲取序列化數據 {'image': None, 'btitle': '西遊記', 'id': 5, 'bread': 10, 'bcomment': 10, 'bpub_date': '1988-01-01'} return HttpResponse('ok')
若是要被序列化的是包含多條數據的查詢集QuerySet,能夠經過添加many=True參數補充說明
def test(request): book = BookInfo.objects.all() # 先查詢出一個圖書對象 serializer = BookInfoSerializer(book, many=True) # 構建序列化 print(serializer.data) # 獲取序列化數據 {'image': None, 'btitle': '西遊記', 'id': 5, 'bread': 10, 'bcomment': 10, 'bpub_date': '1988-01-01'} return HttpResponse('ok')
若是須要序列化的數據中包含有其餘關聯對象,則對關聯對象數據的序列化須要指明。
例如,在定義英雄數據的序列化器時,外鍵hbook(即所屬的圖書)字段如何序列化?
咱們先定義HeroInfoSerialzier除外鍵字段外的其餘部分
對於關聯字段,能夠採用如下幾種方式:
此字段將被序列化爲關聯對象的主鍵。
hbook = serializers.PrimaryKeyRelatedField(label='圖書', read_only=True) 或 hbook = serializers.PrimaryKeyRelatedField(label='圖書', queryset=BookInfo.objects.all())
指明字段時須要包含read_only=True或者queryset參數:
使用效果:
def test(request): hero = HeroInfo.objects.get(id=10) # 查詢一個英雄對象 serializer = HeroInfoSerializer(hero) # 構建序列化 print(serializer.data) # 返回序列化內容 {'id': 10, 'hcomment': '獨孤九劍', 'hname': '令狐沖', 'hbook': 3, 'hgender': 1} return HttpResponse('ok')
報錯:說明id不存在
此字段將被序列化爲關聯對象的字符串表示方式(即__str__方法的返回值)
hbook = serializers.StringRelatedField(label='圖書')
def test(request): hero = HeroInfo.objects.get(id=11) # 查詢一個英雄對象 serializer = HeroInfoSerializer(hero) # 構建序列化 print(serializer.data) # 返回序列化內容 {'hgender': 0, 'hbook': '笑傲江湖', 'id': 11, 'hname': '任盈盈', 'hcomment': '彈琴'} return HttpResponse('ok')
hbook = BookInfoSerializer()
def test(request): hero = HeroInfo.objects.get(id=11) # 查詢一個英雄對象 serializer = HeroInfoSerializer(hero) # 構建序列化 print(serializer.data) # 返回序列化內容 {'hgender': 0, 'hbook': OrderedDict([('id', 3), ('btitle', '笑傲江湖'), ('bpub_date', '1995-12-24'), ('bread', 20), ('bcomment', 80), ('image', None)]), 'hcomment': '彈琴', 'id': 11, 'hname': '任盈盈'} return HttpResponse('ok')
此字段將被序列化爲獲取關聯對象數據的接口連接
hbook = serializers.HyperlinkedRelatedField(label='圖書', read_only=True, view_name='books-detail')
必須指明view_name參數,以便DRF根據視圖名稱尋找路由,進而拼接成完整URL。
{'id': 6, 'hname': '喬峯', 'hgender': 1, 'hcomment': '降龍十八掌', 'hbook': 'http://127.0.0.1:8000/books/2/'}
此字段將被序列化爲關聯對象的指定字段數據
slug_field指明使用關聯對象的哪一個字段
hbook = serializers.SlugRelatedField(label='圖書', read_only=True, slug_field='bpub_date')
def test(request): hero = HeroInfo.objects.get(id=11) # 查詢一個英雄對象 serializer = HeroInfoSerializer(hero) # 構建序列化 print(serializer.data) # 返回序列化內容 {'id': 11, 'hgender': 0, 'hcomment': '彈琴', 'hname': '任盈盈', 'hbook': datetime.date(1995, 12, 24)} return HttpResponse('ok')
序列化器的每一個字段實際都是由該字段類型的to_representation方法決定格式的,能夠經過重寫該方法來決定格式。
注意,to_representations方法不只侷限在控制關聯對象格式上,適用於各個序列化器字段類型。
自定義一個新的關聯字段:
class BookRelateField(serializers.RelatedField): """自定義用於處理圖書的字段""" def to_representation(self, value): return 'Book: %d %s' % (value.id, value.btitle)
hbook = BookRelateField(read_only=True)
def test(request): hero = HeroInfo.objects.get(id=11) # 查詢一個英雄對象 serializer = HeroInfoSerializer(hero) # 構建序列化 print(serializer.data) # 返回序列化內容 {'hbook': 'Book: 3 笑傲江湖', 'id': 11, 'hcomment': '彈琴', 'hname': '任盈盈', 'hgender': 0} return HttpResponse('ok')
若是關聯的對象數據不是隻有一個,而是包含多個數據,如想序列化圖書BookInfo數據,每一個BookInfo對象關聯的英雄HeroInfo對象可能有多個,此時關聯字段類型的指明仍可以使用上述幾種方式,只是在聲明關聯字段時,多補充一個many=True參數便可。
此處僅拿PrimaryKeyRelatedField類型來舉例,其餘相同。
在BookInfoSerializer中添加關聯字段:
class BookInfoSerializer(serializers.Serializer):
"""圖書數據序列化器"""
id = serializers.IntegerField(label='ID', read_only=True)
btitle = serializers.CharField(label='名稱', max_length=20)
bpub_date = serializers.DateField(label='發佈日期', required=False)
bread = serializers.IntegerField(label='閱讀量', required=False)
bcomment = serializers.IntegerField(label='評論量', required=False)
image = serializers.ImageField(label='圖片', required=False)
heroinfo_set = serializers.PrimaryKeyRelatedField(read_only=True, many=True) # 新增
使用效果:
def test(request): book = BookInfo.objects.get(id=3) # 查詢一個英雄對象 serializer = BookInfoSerializer(book) # 構建序列化 print(serializer.data) # 返回序列化內容 {'image': None, 'id': 3, 'bpub_date': '1995-12-24', 'bcomment': 80, 'bread': 20, 'heroinfo_set': [10, 11, 12, 13], 'btitle': '笑傲江湖'} return HttpResponse('ok')