DRF 序列化组件
一. DRF序列化
django自帶有序列化組件,但是相比rest_framework的序列化較差,所以這就不提django自帶的序列化組件了。
首先rest_framework的序列化組件使用同from組件有點(diǎn)類似,當(dāng)反序列化前端返回的數(shù)據(jù)之后,需要先調(diào)用is_valid進(jìn)行校驗(yàn),其中也有局部鉤子validate_字段名,全局鉤子validate,is_valid校驗(yàn)過后才可調(diào)用.data與.errors。
rest_framework有兩種序列化方式,分別是繼承Serializer和ModelSerializer,如果序列化的數(shù)據(jù)是多條時(shí),一定要指定many=True,不然會(huì)報(bào)錯(cuò)。many=True與False的區(qū)別是前者返回列表套字典,而后者只有一個(gè)字典,即就一條數(shù)據(jù)。
from rest_framework.serializers import Serializer, ModelSerializer?1.1 繼承Serializer的序列化
models.py中代碼如下:
from django.db import models# Create your models here.class Book(models.Model):title = models.CharField(max_length=32)price = models.IntegerField()# db_constraint=False時(shí),一對多表只存在邏輯上的關(guān)系,處理數(shù)據(jù)無需考慮外鍵關(guān)系,但是依舊可以正常使用ORM# on_delete在django1版本中默認(rèn)是CASCADE,即級(jí)聯(lián)刪除。on_delete有四種選擇,SET_NULL即外鍵對應(yīng)一表# 數(shù)據(jù)刪除時(shí),將該字段設(shè)置為空,需要設(shè)置null=True或default# related_name='反向查詢的依據(jù)名字'# 外鍵對應(yīng)的表點(diǎn)該依據(jù)名字.all來查詢多關(guān)系表的數(shù)據(jù),不需要表名小寫+_set.all來獲取publish = models.ForeignKey("Publish", related_name='books', db_constraint=False, on_delete=models.SET_NULL, null=True)authors = models.ManyToManyField("Author", db_constraint=False)def __str__(self):return self.titleclass Publish(models.Model):name = models.CharField(max_length=32)email = models.EmailField()def __str__(self):return self.nameclass Author(models.Model):name = models.CharField(max_length=32)age = models.IntegerField()def __str__(self):return self.name序列化類BookSerializer如下:
class BookSerializer(serializers.Serializer):title = serializers.CharField(max_length=32)price = serializers.IntegerField()# source的作用很強(qiáng)大,其中的值相當(dāng)于self.publish.name,# 當(dāng)有字段使用choices屬性時(shí),可以指定source='get_字段名_display'來直接獲取對應(yīng)的值# source 如果是字段,會(huì)顯示字段,如果是方法,會(huì)執(zhí)行方法,不用加括號(hào)publish = serializers.CharField(source='publish.name')# 可以指定一個(gè)函數(shù),函數(shù)名固定get_字段名,函數(shù)return的值就是該字段的值# read_only是反序列化時(shí)不傳,write_only是序列化時(shí)不顯示author_detail = serializers.SerializerMethodField(read_only=True)# 該函數(shù)return的值就是author_detail字段的值def get_author_detail(self, book_obj):authors = book_obj.authors.all()# 函數(shù)內(nèi)部可以直接調(diào)用其他序列化類return AuthorSerializer(authors, many=True).data# 局部鉤子def validate_title(self, value): # value是當(dāng)前的title的值from rest_framework import exceptionsif 'h' in value:# 這是將校驗(yàn)未通過的信息存入序列化obj.errors中raise exceptions.ValidationError('h是不可能h的')return value# 全局鉤子def validate(self, attrs): # attrs是包含了所有字段及數(shù)據(jù)的字典from rest_framework import exceptionsif attrs.get('title') == attrs.get('price'):return attrselse:raise exceptions.ValidationError('書名怎么和價(jià)格一樣')注意,無論是局部鉤子還是全局鉤子函數(shù),都要序列化對象走is_valid方法時(shí)才會(huì)觸發(fā),而且全局要所有需要序列化的字段通過校驗(yàn)才會(huì)觸發(fā)。
上述需要的AuthorSerializer如下:
# 作者Author序列化類 class AuthorSerializer(serializers.Serializer):name = serializers.CharField(max_length=32)age = serializers.IntegerField()在表中寫入數(shù)據(jù)后,在視圖views.py中寫CBV繼承ListAPIView:
from rest_framework.generics import ListAPIView from app01 import models from app01 import app01serializers # Create your views here.class BookAPIView(ListAPIView):queryset = models.Book.objectsserializer_class = app01serializers.BookSerializer然后開路由:
from django.conf.urls import url from django.contrib import admin from app01 import viewsurlpatterns = [url(r'^admin/', admin.site.urls),url(r'^books/', views.BookAPIView.as_view()), ]隨后用postman測試該接口:
這里要注意,如果是前端往后端提交post請求創(chuàng)建新的數(shù)據(jù)時(shí),要反序列化,然后調(diào)用is_valid校驗(yàn)數(shù)據(jù),之后才能調(diào)用.dada與.errors。因?yàn)槔^承Serializer是沒有指定表的,我們需要在對應(yīng)的序列化類中重寫create方法,將.dada當(dāng)create的參數(shù)傳入,然后create中寫保存的邏輯,如果涉及到多表,那么要全靠自己邏輯去寫了,在視圖中執(zhí)行is_valid前將其他表需要的參數(shù)取出執(zhí)行保存操作即可。
反序列時(shí)需要把將參數(shù)指定給data:
bs=BookSerializer(data=request.data)? 如果intence參數(shù)和data參數(shù)都給予了值,那么會(huì)執(zhí)行更新操作:
def put(self, request, pk):book_obj = models.Book.objects.filter(pk=pk).first()bs=BookSerializers(data=request.data, instance=book_obj)if bs.is_valid():bs.save() # updatereturn Response(bs.data)else:return Response(bs.errors)?1.2 繼承ModelSerializer的序列化
繼承Modelserializer的序列化比較方便,因?yàn)椴恍枰饌€(gè)寫字段及字段的類型等。
序列化類如下:
class BookSerializer(serializers.ModelSerializer):# 生成publish_detail的第三種方式publish = PublishSerializer()class Meta:model = models.Book# fields = '__all__' 所有字段序列化,不過一般我們不會(huì)使用該方式# 一般采用下列方式,里面可以填表擁有的字段,# 也可以寫該表中外鍵字段、多對多表正向或反向?qū)?yīng)點(diǎn)語法采用的字段# 其中反向查詢時(shí)我們一般采用.表名小寫的方式,可以在Foreign中設(shè)置字段related_name='反向查詢點(diǎn)語法后的名稱'# 比如Book表中外鍵字段publish設(shè)置屬性related_name='books',那么Publish表反向查詢書籍時(shí),# .books_all()即可拿到該出版社出版的所有書籍對象(不然要寫.book_set.all())fields = ['title', 'price', 'publish', 'author_detail']# exclude=('title',) #拿出除了title的所有字段,不能跟fields同時(shí)用# depth = 1 #深度控制,寫 幾 往里拿幾層,層數(shù)越多,響應(yīng)越慢,官方建議0--10之間,個(gè)人建議最多3層繼承ModelSerializer的類也可以寫全局鉤子、局部鉤子,以及對字段進(jìn)行處理,不過已訂購要寫在class Meta的外面。
fields中可以寫模型表帶有的字段,包含外鍵字段及ManyToMany字段,當(dāng)指定了related_name時(shí),反向查詢的表可以寫related_name指定的名字來訪問另一張表。
這里提一嘴,rest_framework提供了深度屬性depth,但是不建議使用,因?yàn)椴豢煽匦蕴珡?qiáng)。一般涉及到多表時(shí),我們都在模型表中進(jìn)行,比如此處的author_detail,是多對多關(guān)系表中book對應(yīng)的所有author對象,我們在Book模型表中增加以下方法:
@property def author_detail(self):result_list = []authors = self.authors.all()for author in authors:dic = {'name': author.name, 'age': author.age}result_list.append(dic)return result_list上面publish也可以在模型表中定義,比如寫publish_detail:
# 生成publish_detail方式一 @property def publish_detail(self):publish_obj = self.publishreturn {'name': publish_obj.name, 'email': publish_obj.email}# 生成publish_detail方式二 @property def publish_detail(self):from app01 import app01serializerspublish_obj = self.publishreturn app01serializers.PublishSerializer(publish_obj).data然后將序列化類中的publish改為publish_detail,用postman測試接口:
結(jié)果是一樣的,繼承ModelSerializer因?yàn)樾枰付P捅?#xff0c;所有不需要重寫create方法,直接調(diào)用.save方法即可。
1.3 模型層中參數(shù)的補(bǔ)充
比如當(dāng)我們創(chuàng)建外鍵關(guān)系與多對多關(guān)系表時(shí),django 1.x版本默認(rèn)都是級(jí)聯(lián)刪除的,即on_delete=CASCADE,而django 2.x版本需要自己指定。
on_delete一共有四個(gè)值可以選擇:
1. on_delete = models.SET_NULL # 關(guān)聯(lián)表字段刪除后,該ForeignKey字段的值置為空,需要設(shè)置null=True或者是設(shè)置default 2. on_delete = models.SET_DEFAULT # 關(guān)聯(lián)表字段刪除后,該ForeignKey字段的值置為默認(rèn)值,需要設(shè)置default字段 3. on_delete = models.DO_NOTHING # 關(guān)聯(lián)表字段刪除后,該ForeignKey字段的值不變 4. on_delete = models.CASCADE # 關(guān)聯(lián)表字段刪除后,級(jí)聯(lián)刪除? Foreign與ManyToMany字段還有db_constraint與related_name字段。指定db_constraint=False時(shí),一對多的表只存在邏輯上的關(guān)系(此時(shí)數(shù)據(jù)庫如navicat中表關(guān)系圖它們之間的線會(huì)斷開),處理數(shù)據(jù)無需考慮外鍵關(guān)系,不過依舊可以使用ORM正常操作正反向查詢等。
指定related_name字段時(shí),反向查詢無需按表名小寫的方式,直接點(diǎn)該related_name定義的字段即可。舉例,比如Book表與Author表一對多,外鍵在Book表中,那么Author查詢Book表的數(shù)據(jù)就是反向查詢,需要author_obj.book_set.all()獲取作者對應(yīng)的所有書籍?dāng)?shù)據(jù)。這時(shí)指定related_name='books',那么只需采用author_obj.books.all()即可。
如果不清楚可以再看看該博客:https://www.cnblogs.com/liuqingzheng/articles/9766376.html
?
轉(zhuǎn)載于:https://www.cnblogs.com/maoruqiang/p/11228922.html
總結(jié)
- 上一篇: 2019招商银行M-Geeker线上比赛
- 下一篇: 在Jenkins中获取GitHub对应R