DRF 序列化组件
一. DRF序列化
django自帶有序列化組件,但是相比rest_framework的序列化較差,所以這就不提django自帶的序列化組件了。
首先rest_framework的序列化組件使用同from組件有點類似,當反序列化前端返回的數據之后,需要先調用is_valid進行校驗,其中也有局部鉤子validate_字段名,全局鉤子validate,is_valid校驗過后才可調用.data與.errors。
rest_framework有兩種序列化方式,分別是繼承Serializer和ModelSerializer,如果序列化的數據是多條時,一定要指定many=True,不然會報錯。many=True與False的區別是前者返回列表套字典,而后者只有一個字典,即就一條數據。
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時,一對多表只存在邏輯上的關系,處理數據無需考慮外鍵關系,但是依舊可以正常使用ORM# on_delete在django1版本中默認是CASCADE,即級聯刪除。on_delete有四種選擇,SET_NULL即外鍵對應一表# 數據刪除時,將該字段設置為空,需要設置null=True或default# related_name='反向查詢的依據名字'# 外鍵對應的表點該依據名字.all來查詢多關系表的數據,不需要表名小寫+_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的作用很強大,其中的值相當于self.publish.name,# 當有字段使用choices屬性時,可以指定source='get_字段名_display'來直接獲取對應的值# source 如果是字段,會顯示字段,如果是方法,會執行方法,不用加括號publish = serializers.CharField(source='publish.name')# 可以指定一個函數,函數名固定get_字段名,函數return的值就是該字段的值# read_only是反序列化時不傳,write_only是序列化時不顯示author_detail = serializers.SerializerMethodField(read_only=True)# 該函數return的值就是author_detail字段的值def get_author_detail(self, book_obj):authors = book_obj.authors.all()# 函數內部可以直接調用其他序列化類return AuthorSerializer(authors, many=True).data# 局部鉤子def validate_title(self, value): # value是當前的title的值from rest_framework import exceptionsif 'h' in value:# 這是將校驗未通過的信息存入序列化obj.errors中raise exceptions.ValidationError('h是不可能h的')return value# 全局鉤子def validate(self, attrs): # attrs是包含了所有字段及數據的字典from rest_framework import exceptionsif attrs.get('title') == attrs.get('price'):return attrselse:raise exceptions.ValidationError('書名怎么和價格一樣')注意,無論是局部鉤子還是全局鉤子函數,都要序列化對象走is_valid方法時才會觸發,而且全局要所有需要序列化的字段通過校驗才會觸發。
上述需要的AuthorSerializer如下:
# 作者Author序列化類 class AuthorSerializer(serializers.Serializer):name = serializers.CharField(max_length=32)age = serializers.IntegerField()在表中寫入數據后,在視圖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請求創建新的數據時,要反序列化,然后調用is_valid校驗數據,之后才能調用.dada與.errors。因為繼承Serializer是沒有指定表的,我們需要在對應的序列化類中重寫create方法,將.dada當create的參數傳入,然后create中寫保存的邏輯,如果涉及到多表,那么要全靠自己邏輯去寫了,在視圖中執行is_valid前將其他表需要的參數取出執行保存操作即可。
反序列時需要把將參數指定給data:
bs=BookSerializer(data=request.data)? 如果intence參數和data參數都給予了值,那么會執行更新操作:
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的序列化比較方便,因為不需要逐個寫字段及字段的類型等。
序列化類如下:
class BookSerializer(serializers.ModelSerializer):# 生成publish_detail的第三種方式publish = PublishSerializer()class Meta:model = models.Book# fields = '__all__' 所有字段序列化,不過一般我們不會使用該方式# 一般采用下列方式,里面可以填表擁有的字段,# 也可以寫該表中外鍵字段、多對多表正向或反向對應點語法采用的字段# 其中反向查詢時我們一般采用.表名小寫的方式,可以在Foreign中設置字段related_name='反向查詢點語法后的名稱'# 比如Book表中外鍵字段publish設置屬性related_name='books',那么Publish表反向查詢書籍時,# .books_all()即可拿到該出版社出版的所有書籍對象(不然要寫.book_set.all())fields = ['title', 'price', 'publish', 'author_detail']# exclude=('title',) #拿出除了title的所有字段,不能跟fields同時用# depth = 1 #深度控制,寫 幾 往里拿幾層,層數越多,響應越慢,官方建議0--10之間,個人建議最多3層繼承ModelSerializer的類也可以寫全局鉤子、局部鉤子,以及對字段進行處理,不過已訂購要寫在class Meta的外面。
fields中可以寫模型表帶有的字段,包含外鍵字段及ManyToMany字段,當指定了related_name時,反向查詢的表可以寫related_name指定的名字來訪問另一張表。
這里提一嘴,rest_framework提供了深度屬性depth,但是不建議使用,因為不可控性太強。一般涉及到多表時,我們都在模型表中進行,比如此處的author_detail,是多對多關系表中book對應的所有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測試接口:
結果是一樣的,繼承ModelSerializer因為需要指定模型表,所有不需要重寫create方法,直接調用.save方法即可。
1.3 模型層中參數的補充
比如當我們創建外鍵關系與多對多關系表時,django 1.x版本默認都是級聯刪除的,即on_delete=CASCADE,而django 2.x版本需要自己指定。
on_delete一共有四個值可以選擇:
1. on_delete = models.SET_NULL # 關聯表字段刪除后,該ForeignKey字段的值置為空,需要設置null=True或者是設置default 2. on_delete = models.SET_DEFAULT # 關聯表字段刪除后,該ForeignKey字段的值置為默認值,需要設置default字段 3. on_delete = models.DO_NOTHING # 關聯表字段刪除后,該ForeignKey字段的值不變 4. on_delete = models.CASCADE # 關聯表字段刪除后,級聯刪除? Foreign與ManyToMany字段還有db_constraint與related_name字段。指定db_constraint=False時,一對多的表只存在邏輯上的關系(此時數據庫如navicat中表關系圖它們之間的線會斷開),處理數據無需考慮外鍵關系,不過依舊可以使用ORM正常操作正反向查詢等。
指定related_name字段時,反向查詢無需按表名小寫的方式,直接點該related_name定義的字段即可。舉例,比如Book表與Author表一對多,外鍵在Book表中,那么Author查詢Book表的數據就是反向查詢,需要author_obj.book_set.all()獲取作者對應的所有書籍數據。這時指定related_name='books',那么只需采用author_obj.books.all()即可。
如果不清楚可以再看看該博客:https://www.cnblogs.com/liuqingzheng/articles/9766376.html
?
轉載于:https://www.cnblogs.com/maoruqiang/p/11228922.html
總結
- 上一篇: 2019招商银行M-Geeker线上比赛
- 下一篇: 在Jenkins中获取GitHub对应R