做puzzle的網(wǎng)站香飄飄奶茶軟文
系列文章目錄
- Django入門(mén)全攻略:從零搭建你的第一個(gè)Web項(xiàng)目
- Django ORM入門(mén)指南:從概念到實(shí)踐,掌握模型創(chuàng)建、遷移與視圖操作
- Django ORM實(shí)戰(zhàn):模型字段與元選項(xiàng)配置,以及鏈?zhǔn)竭^(guò)濾與QF查詢?cè)斀?/li>
- Django ORM深度游:探索多對(duì)一、一對(duì)一與多對(duì)多數(shù)據(jù)關(guān)系的奧秘與實(shí)踐
- 跨域問(wèn)題與Django解決方案:深入解析跨域原理、請(qǐng)求處理與CSRF防護(hù)
- Django視圖層探索:GET/POST請(qǐng)求處理、參數(shù)傳遞與響應(yīng)方式詳解
- Django路由與會(huì)話深度探索:靜態(tài)、動(dòng)態(tài)路由分發(fā),以及Cookie與Session的奧秘
- Django API開(kāi)發(fā)實(shí)戰(zhàn):前后端分離、Restful風(fēng)格與DRF序列化器詳解
- Django REST framework序列化器詳解:普通序列化器與模型序列化器的選擇與運(yùn)用
- 還在寫(xiě)0.0…
文章目錄
- 系列文章目錄
- 前言
- 一、普通序列化器-Serializer
- 1. 普通序列化器編寫(xiě)方式
- 2. 普通序列化器序列化
- 3. 普通序列化器反序列化創(chuàng)建
- 4. 普通序列化器反序列化更新
- 5. 普通序列化器完整代碼
- 二、模型序列化器-ModelSerializer
- 1. 模型序列化器編寫(xiě)方式
- 2. 模型序列化器反序列化創(chuàng)建、更新
- 3. 模型序列化器與普通序列化器的對(duì)比
前言
????在 Django REST framework 中,數(shù)據(jù)序列化至關(guān)重要。本文將探討 普通序列化器 和 模型序列化器,了解它們的基本功能和差異,幫助您根據(jù)項(xiàng)目需求選擇合適的序列化器。
Response是不能直接返回ORM數(shù)據(jù)的,所以需要我們進(jìn)行序列化操作,可以通過(guò)手動(dòng)將其轉(zhuǎn)為字典或JSON,也可以使用DRF所提供的序列化器,一般建議使用序列化器。
如果你經(jīng)常使用的是自己去將數(shù)據(jù)封裝為JSON,那么常見(jiàn)的代碼模型就像這樣
data = models.objects.all()
json_data = {}
for d in data:json_data['age'] = d.agejson_data['name'] = d.name
return Response(json_data)
隨字段越來(lái)越多,工作量會(huì)越來(lái)越大,而且有關(guān)于時(shí)間(DateTimeField、DateField)等字段類型的序列化直接通過(guò)JSON也是不行的,需要自己手動(dòng)編寫(xiě)JSON的序列化器,非常麻煩,于是乎 DRF 就提供了更為便捷的兩種序列化器,普通序列化器與模型序列化器
一、普通序列化器-Serializer
1. 普通序列化器編寫(xiě)方式
導(dǎo)包:
from rest_framework import serializers
普通序列化器,可以按照給定字段,將所匹配的ORM數(shù)據(jù)字段轉(zhuǎn)換為JSON數(shù)據(jù),不光可以對(duì)一條數(shù)據(jù),也可以對(duì)一個(gè)QuerySet所對(duì)應(yīng)的結(jié)果集
例如:
用戶表 UserModel:
#models.py
from django.db import models# Create your models here.
class UserModel(models.Model):name = models.CharField(max_length=50)phone = models.CharField(max_length=11)password = models.CharField(max_length=30)info = models.CharField(max_length=100, null=True)def __str__(self):return self.nameclass Meta:db_table = 'user'
普通序列化器UserSerializer定義如下:
#userSerializer.py
class UserSerializer(serializers.Serializer):name = serializers.CharField(max_length=50)phone = serializers.CharField(validators=[validators_phone])password = serializers.CharField(max_length=30)info = serializers.CharField(max_length=100,default="默認(rèn)值")
序列化器的使用分兩個(gè)階段:
1、在客戶端請(qǐng)求時(shí),使用序列化器可以完成對(duì)數(shù)據(jù)的反序列化(將字典格式的數(shù)據(jù)轉(zhuǎn)化為模型對(duì)象)。
2、在服務(wù)器響應(yīng)時(shí),使用序列化器可以完成對(duì)數(shù)據(jù)的序列化(將模型對(duì)象轉(zhuǎn)化為字典格式的數(shù)據(jù))。
2. 普通序列化器序列化
序列化就是將ORM數(shù)據(jù)放入序列化器加工,誕生出JSON數(shù)據(jù)對(duì)象,序列化器對(duì)象的data
屬性即為處理好的 JSON 數(shù)據(jù)對(duì)象
1、單條數(shù)據(jù)的序列化:
- 單挑數(shù)據(jù)的序列化很簡(jiǎn)單,直接通過(guò)序列化器類對(duì)象的參數(shù)
instance
傳入查詢得到的結(jié)果即可
#views.py
class UserIdView(APIView):def get(self, request, id):user = UserModel.objects.get(pk=id)usSer = UserSerializer(instance=user)return Response({"message": "get測(cè)試成功!", "data": usSer.data})
2、多條數(shù)據(jù)的序列化:
- 如果使用像filter、all這樣的一些ORM方法,獲取到的是QuerySet結(jié)果集,不是單獨(dú)數(shù)據(jù)對(duì)象,那么使用序列化器時(shí),需要傳入many=True參數(shù),用來(lái)表示:傳入的不止一條數(shù)據(jù)。
#views.py
class UserView(APIView):def get(self, request):users = UserModel.objects.all()usSer = UserSerializer(instance=users, many=True)return Response({"message":"get測(cè)試成功!","data":usSer.data})
Serializer屬性中選項(xiàng)參數(shù)
選項(xiàng)參數(shù)名稱 | 作用 |
---|---|
max_length | 最大長(zhǎng)度 |
min_length | 最小長(zhǎng)度 |
allow_blank | 是否允許為空 |
trim_whitespace | 是否截?cái)嗫瞻鬃址?/td> |
max_value | 最大值 |
min_value | 最小值 |
通用參數(shù)名稱 | 作用 |
---|---|
read_only | 該字段僅用于序列化輸出,需要序列化輸出時(shí)設(shè)置:read_only=True;默認(rèn)為False |
write_only | 該字段僅用于反序列輸入,需要序列化輸入時(shí)設(shè)置:write_only=True;默認(rèn)為False |
required | 該字段表示在反序列化輸入時(shí)必須輸入 |
default | 反序列化時(shí)使用的默認(rèn)值 |
allow_null | 表明該字段是否允許傳入None,默認(rèn)False |
validators | 對(duì)字段進(jìn)行校驗(yàn),定義在字段中 |
error_message | 當(dāng)字段校驗(yàn)不通過(guò)時(shí),報(bào)error_message的value值 |
label | 用于HTML展示API頁(yè)面時(shí),顯示的字段名稱 |
help_text | 用于HTML展示API頁(yè)面時(shí),顯示的字段幫助提示信息 |
3. 普通序列化器反序列化創(chuàng)建
反序列化的概念很簡(jiǎn)單,就是把
JSON
等數(shù)據(jù)變?yōu)?code>ORM數(shù)據(jù)對(duì)象,甚至是入庫(kù)或者是修改
DRF要求序列化器必須對(duì)數(shù)據(jù)進(jìn)行校驗(yàn),才能獲取驗(yàn)證成功的數(shù)據(jù)或保存成模型類對(duì)象
- 在操作過(guò)程中,反序列化首先需要通過(guò)
data
傳參- 接著調(diào)用
is_valid
進(jìn)行校驗(yàn),驗(yàn)證成功返回True
,反之返回False
- 如果校驗(yàn)失敗,還可以通過(guò)結(jié)果的
errors
屬性返回錯(cuò)誤值is_valid
調(diào)用后方法會(huì)進(jìn)行字段屬性(max_value=10)
的校驗(yàn)、自定義的校驗(yàn)等等- 對(duì)校驗(yàn)過(guò)后的對(duì)象調(diào)用
save
方法,這個(gè)save
方法會(huì)觸發(fā)序列化器中的create
方法
- 普通序列化器中,
create
方法默認(rèn)是沒(méi)有實(shí)現(xiàn)的,需要手動(dòng)根據(jù)模型類進(jìn)行編寫(xiě)
如果需要自定義校驗(yàn)規(guī)則,可以通過(guò)
validators
實(shí)現(xiàn):
#userSerializer.py
from rest_framework import serializers
from app.models import UserModel
import redef validators_phone(values):r_phone = r"^1[3-9]\d{9}$"if re.match(r_phone, values):print("手機(jī)號(hào)匹配成功!")else:print("手機(jī)號(hào)匹配失敗,拋出異常!")raise serializers.ValidationError("手機(jī)號(hào)匹配失敗!不滿足規(guī)則!")class UserSerializer(serializers.Serializer):name = serializers.CharField(max_length=50)phone = serializers.CharField(validators=[validators_phone])password = serializers.CharField(max_length=30)info = serializers.CharField(max_length=100,default="默認(rèn)值")
比如現(xiàn)在,需要提交數(shù)據(jù)用到創(chuàng)建User的接口,此時(shí)可以這么做
為了能夠保證數(shù)據(jù)成功入庫(kù),默認(rèn)的普通序列化器是不具備入庫(kù)功能的,需要編寫(xiě)create
方法
#userSerializer.py
class UserSerializer(serializers.Serializer):name = serializers.CharField(max_length=50)phone = serializers.CharField(validators=[validators_phone])password = serializers.CharField(max_length=30)info = serializers.CharField(max_length=100,default="默認(rèn)值")def create(self, validated_data):object = UserModel.objects.create(**validated_data)return object#具體來(lái)說(shuō),**validated_data的作用是:解包字典。
#它將validated_data字典中的鍵值對(duì)解包為一系列的關(guān)鍵字參數(shù)。
成功之后,就可以通過(guò)像之前一樣的數(shù)據(jù)提交,編寫(xiě)視圖完成數(shù)據(jù)入庫(kù),序列化器可以直接處理request所提交的數(shù)據(jù)data,并且可以剔除在request.data中其他多余的字段,只會(huì)處理序列化器里的字段
# views.py
class UserView(APIView):def post(self, request):ser = UserSerializer(data=request.data) # 傳參data,進(jìn)行反序列化if ser.is_valid():print("校驗(yàn)成功!")ser.save()return Response({"message":"[POST]信息添加成功!"})else:print("校驗(yàn)失敗!")return Response({"message": ser.errors})
4. 普通序列化器反序列化更新
反序列化經(jīng)過(guò)校驗(yàn)的數(shù)據(jù),不光可以用來(lái)創(chuàng)建數(shù)據(jù),還可以用來(lái)更新數(shù)據(jù)
- 更新首先需要一個(gè)已經(jīng)存在的數(shù)據(jù),所以需要通過(guò)
instance
參數(shù)傳遞已有的一個(gè)ORM對(duì)象- 還需要待更新的新值,那么就需要傳
data
參數(shù)- 之后同樣需要
is_valid
方法調(diào)用,檢查即將更新進(jìn)入的數(shù)據(jù)是否合法- 最終
save
觸發(fā)序列化器中的update
方法
默認(rèn)普通序列化器是沒(méi)有自帶對(duì)于數(shù)據(jù)的更新方法的,現(xiàn)在需要在序列化器里創(chuàng)建
update
方法
# userSerializer.py
class UserSerializer(serializers.Serializer):name = serializers.CharField(max_length=50)phone = serializers.CharField(validators=[validators_phone])password = serializers.CharField(max_length=30)info = serializers.CharField(max_length=100,default="默認(rèn)值")def update(self, instance, validated_data):# instance 要更新的數(shù)據(jù),validated_data 是新數(shù)據(jù)instance.name = validated_data.get('name', instance.name)instance.phone = validated_data.get('phone', instance.phone)instance.password = validated_data.get('password', instance.password)instance.info = validated_data.get('info', instance.info)instance.save()return instance#獲取字段值:
#validated_data.get('name') 嘗試從 validated_data 字典中獲取鍵為 'name' 的值。
#validated_data 是由序列化器在驗(yàn)證請(qǐng)求數(shù)據(jù)后生成的一個(gè)字典,它包含了經(jīng)過(guò)驗(yàn)證的字段和它們的值。#默認(rèn)值機(jī)制:
#get 方法有一個(gè)可選的第二個(gè)參數(shù),即默認(rèn)值。如果 'name' 這個(gè)鍵不存在于validated_data 中,get 方法將返回這個(gè)默認(rèn)值。
#在這個(gè)例子中,如果請(qǐng)求數(shù)據(jù)中沒(méi)有包含 'name' 字段,那么默認(rèn)值就是 instance.name,即當(dāng)前模型實(shí)例的 name 字段的值。
然后通過(guò)PUT
傳遞要更新數(shù)據(jù)的ID
,以及更新后的值,來(lái)為某條數(shù)據(jù)更新
class UserIdView(APIView):def put(self, request, id):user = UserModel.objects.get(pk=id)ser = UserSerializer(instance=user, data=request.data)if ser.is_valid():print("校驗(yàn)成功!")ser.save()return Response({"message": "[PUT]信息修改成功!"})else:print("校驗(yàn)失敗!")return Response({"message": ser.errors})
5. 普通序列化器完整代碼
models.py:
from django.db import models# Create your models here.
class UserModel(models.Model):name = models.CharField(max_length=50)phone = models.CharField(max_length=11)password = models.CharField(max_length=30)info = models.CharField(max_length=100, null=True)def __str__(self):return self.nameclass Meta:db_table = 'user'
userSerializer.py:
from rest_framework import serializers
from app.models import UserModel
import redef validators_phone(values):r_phone = r"^1[3-9]\d{9}$"if re.match(r_phone, values):print("手機(jī)號(hào)匹配成功!")else:print("手機(jī)號(hào)匹配失敗,拋出異常!")raise serializers.ValidationError("手機(jī)號(hào)匹配失敗!不滿足規(guī)則!")class UserSerializer(serializers.Serializer):name = serializers.CharField(max_length=50)phone = serializers.CharField(validators=[validators_phone])password = serializers.CharField(max_length=30)info = serializers.CharField(max_length=100,default="默認(rèn)值")def create(self, validated_data):object = UserModel.objects.create(**validated_data)return objectdef update(self, instance, validated_data):# instance 要更新的數(shù)據(jù),validated_data 是新數(shù)據(jù)instance.name = validated_data.get('name', instance.name)instance.phone = validated_data.get('phone', instance.phone)instance.password = validated_data.get('password', instance.password)instance.info = validated_data.get('info', instance.info)instance.save()return instance
views.py:
from rest_framework.views import APIView
from rest_framework.response import Response
from app.models import UserModel
from app.serializer.userSerializer import UserSerializer
from django.shortcuts import render# Create your views here.class UserView(APIView):def get(self, request):users = UserModel.objects.all()usSer = UserSerializer(instance=users, many=True)return Response({"message":"get測(cè)試成功!","data":usSer.data})def post(self, request):ser = UserSerializer(data=request.data) # 傳參data,進(jìn)行反序列化if ser.is_valid():print("校驗(yàn)成功!")ser.save()return Response({"message":"[POST]信息添加成功!"})else:print("校驗(yàn)失敗!")return Response({"message": ser.errors})class UserIdView(APIView):def get(self, request, id):user = UserModel.objects.get(pk=id)usSer = UserSerializer(instance=user)return Response({"message": "get測(cè)試成功!", "data": usSer.data})def put(self, request, id):user = UserModel.objects.get(pk=id)ser = UserSerializer(instance=user, data=request.data)if ser.is_valid():print("校驗(yàn)成功!")ser.save()return Response({"message": "[PUT]信息修改成功!"})else:print("校驗(yàn)失敗!")return Response({"message": ser.errors})
urls.py:
from django.urls import path
from app.views import UserView,UserIdViewurlpatterns = [path('user/', UserView.as_view()),path('user/<int:id>/', UserIdView.as_view()),
]
二、模型序列化器-ModelSerializer
1. 模型序列化器編寫(xiě)方式
之前的普通序列化器,很明顯可以感覺(jué)到,如果模型類字段少了,還行,但是模型字段越來(lái)越多,那么開(kāi)發(fā)者在序列化器里所要復(fù)刻的字段也要越來(lái)越多,很麻煩, 而且還得手動(dòng)實(shí)現(xiàn)
update
和create
方法,而且光寫(xiě)了序列化器字段還不行,還得有字段屬性
于是乎,有了現(xiàn)在的與模型類關(guān)聯(lián)的序列化器,可以更加方便的進(jìn)行字段映射以及內(nèi)置方法的編寫(xiě)
模型類關(guān)聯(lián)序列化器大概總結(jié)有如下三個(gè)特性,一個(gè)缺點(diǎn):
- 特點(diǎn):
- 基于模型類自動(dòng)生成一系列字段
- 自動(dòng)生成的系列字段,同時(shí)還包含
unique
、max_length
等屬性校驗(yàn)- 包含默認(rèn)的
create
和update
的實(shí)現(xiàn)- 缺點(diǎn):
- 不會(huì)自動(dòng)映射模型類字段的
default
屬性
模型類關(guān)聯(lián)的序列化器用的是新的序列化器基類:
from rest_framework.serializers import ModelSerializer
用戶模型類依舊使用上文中的UserModel.py文件
按照之前的普通序列化寫(xiě)法,你需要同步一個(gè)字段,并將字段屬性也要記得同步,非常麻煩,但通過(guò)與模型類關(guān)聯(lián)的序列化器就很簡(jiǎn)單了。
- 首先通過(guò)繼承
ModelSerializer
基類- 通過(guò)序列化器元類屬性中的
model
屬性關(guān)聯(lián)模型類- 通過(guò)序列化器元類屬性中的
fields
屬性指明序列化器需要處理的字段
# userModelSerializer.py
from rest_framework import serializers
from app.models import UserModelclass UserModelSerializer(serializers.ModelSerializer):# 不需要再重寫(xiě) create 和 update 方法了,可查看ModelSerializer源碼class Meta:model = UserModelfields = '__all__' # 指明所有模型類字段# exclude = ('password',) # 排除掉的字段# read_only_fields = ('name','info') # 只用于序列化的字段# fields = ('name','phone','password','info')# extra_kwargs = {# 'info':{'min_length':5, 'required':True},# } #修改原有字段的選項(xiàng)參數(shù)
模型類關(guān)聯(lián)的序列化器和普通的序列化器使用方法一樣,使用序列化器返回當(dāng)前所有的商品數(shù)據(jù),還是像之前一樣傳入instance參數(shù)即可,還要記得由于是多個(gè)商品,不是單獨(dú)數(shù)據(jù),要記得加many=True參數(shù)
2. 模型序列化器反序列化創(chuàng)建、更新
模型序列化器的創(chuàng)建就更簡(jiǎn)單了,不需要手動(dòng)實(shí)現(xiàn)create方法,大致流程如下:
- 為序列化器綁定數(shù)據(jù),
ser=Serializer(data=request.data)
- 校驗(yàn)數(shù)據(jù),
ser.is_valid()
- 存儲(chǔ)入庫(kù),
ser.save()
創(chuàng)建用戶接口:
from rest_framework.views import APIView
from rest_framework.response import Response
from app.models import UserModel
from app.serializer.userModelSerializer import UserModelSerializer# Create your views here.class UserView(APIView):def get(self, request):users = UserModel.objects.all()usSer = UserModelSerializer(instance=users, many=True)return Response({"message":"get測(cè)試成功!","data":usSer.data})def post(self, request):ser = UserModelSerializer(data=request.data) # 傳參data,進(jìn)行反序列化if ser.is_valid():print("校驗(yàn)成功!")ser.save()return Response({"message":"[POST]信息添加成功!"})else:print("校驗(yàn)失敗!")return Response({"message": ser.errors})
注意: 反序列化自動(dòng)生成的字段屬性中,不會(huì)包含原始模型類字段中的default字段屬性
更細(xì)用戶信息接口:
更新某一個(gè)商品數(shù)據(jù),模型序列化器也是自帶了update
方法
class UserIdView(APIView):def get(self, request, id):user = UserModel.objects.get(pk=id)usSer = UserModelSerializer(instance=user)return Response({"message": "get測(cè)試成功!", "data": usSer.data})def put(self, request, id):user = UserModel.objects.get(pk=id)ser = UserModelSerializer(instance=user, data=request.data)if ser.is_valid():print("校驗(yàn)成功!")ser.save()return Response({"message": "[PUT]信息修改成功!"})else:print("校驗(yàn)失敗!")return Response({"message": ser.errors})
3. 模型序列化器與普通序列化器的對(duì)比
- 序列化時(shí),將模型類對(duì)象傳入
instance
參數(shù)- 序列化結(jié)果使用序列化器對(duì)象的
data
屬性獲取得到
- 序列化結(jié)果使用序列化器對(duì)象的
- 反序列化創(chuàng)建時(shí),將要被反序列化的數(shù)據(jù)傳入
data
參數(shù)- 反序列化一定要記得先使用
is_valid
校驗(yàn)
- 反序列化一定要記得先使用
- 反序列化更新時(shí),將要更新的數(shù)據(jù)對(duì)象傳入
instance
參數(shù),更新后的數(shù)據(jù)傳入data
參數(shù) - 模型序列化器比普通序列化器更加方便,自動(dòng)生成序列化映射字段,
create
、update
方法等 - 關(guān)聯(lián)外鍵序列化,字段屬性外鍵為多時(shí)要記得加
many=True