RestFramework之序列化組件
一,自己手動序列化
class Book(APIView): # parser_classes = [FormParser, ] def get(self, request): book_list = models.Book.objects.all() temp = [] for book in book_list: temp.append({"title": book.title, "publish_date": book.publishDate}) # 如果字段較多,不方便return JsonResponse(temp, safe=False) def post(self, request): print("post") print(request.data) return HttpResponse("ok")
二,使用django自帶的序列化
from django.core.serializers import serialize # django自帶的序列化
class Book(APIView): # parser_classes = [FormParser, ]def get(self, request): book_list = models.Book.objects.all() data = serialize("json", book_list) # 格式 print(data) return HttpResponse(data) def post(self, request): print("post") print(request.data) return HttpResponse("ok")
get請求訪問時,返回的數據:
[{"model": "app01.book", "pk": 1, "fields": {"title": "\u897f\u6e38\u8bb0", "price": "123.00", "publishDate": null, "publish": 1, "authors": [1, 2]}}, {"model": "app01.book", "pk": 2, "fields": {"title": "\u4e09\u56fd\u6f14\u4e49", "price": "456.00", "publishDate": null, "publish": 2, "authors": [3]}}, {"model": "app01.book", "pk": 3, "fields": {"title": "\u7ea2\u697c\u68a6", "price": "745.12", "publishDate": null, "publish": 3, "authors": [2]}}, {"model": "app01.book", "pk": 4, "fields": {"title": "\u6c34\u6d52\u4f20", "price": "456.23", "publishDate": null, "publish": 1, "authors": [3]}}]
默認的是這種格式,而且沒有校驗的功能;
三,使用restframework的序列化組件
1, get請求返回數據
from rest_framework.response import Response from rest_framework import serializers class BookSerializer(serializers.Serializer): # 在這個類中寫什麽字段,就序列化什麽字段 title = serializers.CharField(max_length=32) price = serializers.DecimalField(max_digits=5, decimal_places=2) publishDate = serializers.DateField() class Book(APIView): # parser_classes = [FormParser, ] def get(self, request): book_list = models.Book.objects.all() bs = BookSerializer(book_list, many=True) # 實例化上面那個類,傳入一個queryset,mang=True表示很多序列化一條以上的數據 print(bs.data) return Response(bs.data) def post(self, request): print("post") print(request.data) return HttpResponse("ok")
可以看到bs.data是一個列表中 放的一個個的有序字典:
[OrderedDict([(‘title‘, ‘西遊記‘), (‘price‘, ‘123.00‘), (‘publishDate‘, None)]),
OrderedDict([(‘title‘, ‘三國演義‘), (‘price‘, ‘456.00‘), (‘publishDate‘, None)]),
OrderedDict([(‘title‘, ‘紅樓夢‘), (‘price‘, ‘745.12‘), (‘publishDate‘, None)]),
OrderedDict([(‘title‘, ‘水滸傳‘), (‘price‘, ‘456.23‘), (‘publishDate‘, None)])]
在前端響應中的數據是:
[ { "title": "西遊記", "price": "123.00", "publishDate": null }, { "title": "三國演義", "price": "456.00", "publishDate": null }, { "title": "紅樓夢", "price": "745.12", "publishDate": null }, { "title": "水滸傳", "price": "456.23", "publishDate": null } ]
2 ,post提交數據
使用book表:
class Book(models.Model): title = models.CharField(max_length=32) price = models.DecimalField(max_digits=5, decimal_places=2) publishDate = models.DateField(default="2018-09-18") publish = models.ForeignKey(to="Publish", on_delete=models.CASCADE, default=1) authors = models.ManyToManyField(to="Author", default=2) def __str__(self): return self.title
先寫那個序列化類:
對於普通字段:
class BookSerializer(serializers.Serializer): title = serializers.CharField(max_length=32) price = serializers.DecimalField(max_digits=5, decimal_places=2) publishDate = serializers.DateField()
在寫我們的視圖:
class Book(APIView): # parser_classes = [FormParser, ] def get(self, request): book_list = models.Book.objects.all() bs = BookSerializer(book_list, many=True) print(bs.data) return Response(bs.data) def post(self, request): print(request.data) bs = BookSerializer(data=request.data, many=False) # many默認就是False,可以不寫 if bs.is_valid(): # 校驗 # 添加到數據庫, 需要手動創建 models.Book.objects.create(**request.data) return Response(bs.data) # 創建成功,返回創建的數據 else: return Response(bs.errors) # 失敗,返回錯誤信息
序列化的過程:
我們寫了 bs = BookSerializer(data=request.data, many=False) 這句話的時候,
對於bs.data數據:
restframework序列化組件是這樣做的:
temp = [ ]
for obj in book_list:
temp.append({
"title": obj.title, # 這裏面的鍵就是我們寫的字段
"price": obj.price,
"publishDate": obj.publishDate
})
json.dumps(temp),
那麽,如果我們寫了一對多,或者多對多字段,如:
class BookSerializer(serializers.Serializer): title = serializers.CharField(max_length=32) price = serializers.DecimalField(max_digits=5, decimal_places=2) publishDate = serializers.DateField() publish = serializers.CharField(max_length=32) # 一對多關系 authors = serializers.CharField(max_length=32) # 多對多關系
在序列化過程中,就會出現obj.publish, 結果是publish的對象; obj.authors, 結果是管理對象,即 app01.Author.None;
結果如下:
# get請求的結果
[ { "title": "西遊記", "price": "123.00", "publishDate": null, "publish": "沙河出版社", # 顯示的str方法的結果 "authors": "app01.Author.None" }, { "title": "三國演義", "price": "456.00", "publishDate": null, "publish": "西二旗出版社", "authors": "app01.Author.None" }, { "title": "紅樓夢", "price": "745.12", "publishDate": null, "publish": "望京西出版社", "authors": "app01.Author.None" }, { "title": "水滸傳", "price": "456.23", "publishDate": null, "publish": "沙河出版社", "authors": "app01.Author.None" }]
所以,對於一對多的字段:
class BookSerializer(serializers.Serializer): title = serializers.CharField(max_length=32) price = serializers.DecimalField(max_digits=5, decimal_places=2) publishDate = serializers.DateField() publish_email = serializers.CharField(max_length=32, source="publish.email") publish_name = serializers.CharField(max_length=32, source="publish.name") authors = serializers.CharField(max_length=32)
寫上source之後,那裏循環的時候就是采用的obj.source的內容了,所以前面的字段名稱也就不一定要和表對齊了。
# get請求的結果
[ { "title": "西遊記", "price": "123.00", "publishDate": null, "publish_email": "132", "publish_name": "沙河出版社", "authors": "app01.Author.None" }, { "title": "三國演義", "price": "456.00", "publishDate": null, "publish_email": "456", "publish_name": "西二旗出版社", "authors": "app01.Author.None" }]
對於多對多字段,我們當然也可以寫source了,比如:
class BookSerializer(serializers.Serializer): title = serializers.CharField(max_length=32) price = serializers.DecimalField(max_digits=5, decimal_places=2) publishDate = serializers.DateField() publish_email = serializers.CharField(max_length=32, source="publish.email") publish_name = serializers.CharField(max_length=32, source="publish.name") authors = serializers.CharField(max_length=32, source="authors.all")
但是這樣的話前端拿到的就是:
[ { "title": "西遊記", "price": "123.00", "publishDate": null, "publish_email": "132", "publish_name": "沙河出版社", "authors": "<QuerySet [<Author: 覺先生>, <Author: 胡大炮>]>" # 前端根本不能處理queryset類型,所以也就沒有意義了 }]
所以,多對多字段我們這麽寫:
class BookSerializer(serializers.Serializer): title = serializers.CharField(max_length=32) price = serializers.DecimalField(max_digits=5, decimal_places=2) publishDate = serializers.DateField() publish_email = serializers.CharField(max_length=32, source="publish.email") publish_name = serializers.CharField(max_length=32, source="publish.name") # authors = serializers.CharField(max_length=32) authors = serializers.SerializerMethodField() # 多對多字段 def get_authors(self, obj): # 這裏的obj是循環中的書籍對象, 函數名稱必須是 get_多對多字段名 ret = [] for author in obj.authors.all(): ret.append( {"name": author.name, "age": author.age} ) return ret
前端拿到的數據:
[ { "title": "西遊記", "price": "123.00", "publishDate": null, "publish_email": "132", "publish_name": "沙河出版社", "authors": [ # 這樣前端就可以處理了 { "name": "覺先生", "age": 18 }, { "name": "胡大炮", "age": 28 } ] } ]
多對多字段的序列話的時候:
循環時,如果時多對多字段,那麽
temp.append({
"字段名(authors)": get_authors()函數的返回值
});
四, 使用ModelSerializer
from app01 import models from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import serializers class BookSerializer(serializers.ModelSerializer): class Meta: model = models.Book # fields = ["title", "price", "publishDate"] # 可以指定字段 fields = "__all__" # 所有字段 class Book(APIView): # parser_classes = [FormParser, ] def get(self, request): book_list = models.Book.objects.all() bs = BookSerializer(book_list, many=True) print(bs.data) return Response(bs.data) def post(self, request): print(request.data) bs = BookSerializer(data=request.data, many=False) # many默認就是False,可以不寫 if bs.is_valid(): # 校驗 bs.save() # 直接save() return Response(bs.data) # 創建成功,返回創建的數據 else: return Response(bs.errors) # 失敗,返回錯誤信息
get請求數據,結果為:
[ { "id": 1, "title": "西遊記", "price": "123.00", "publishDate": null, "publish": 1, # 默認取得都是主鍵 "authors": [ 1, 2 ] }, { "id": 2, "title": "三國演義", "price": "456.00", "publishDate": null, "publish": 2, "authors": [ 3 ] }, { "id": 3, "title": "紅樓夢", "price": "745.12", "publishDate": null, "publish": 3, "authors": [ 2 ] } ]
我們也可以自己配置, 方法和上面直接使用Serializer一致:
class BookSerializer(serializers.ModelSerializer): class Meta: model = models.Book # fields = ["title", "price", "publishDate"] # 可以指定字段 fields = "__all__" # 所有字段 publish_email = serializers.CharField(max_length=32, source="publish.email") publish_name = serializers.CharField(max_length=32, source="publish.name") authors = serializers.SerializerMethodField() # 多對多字段 def get_authors(self, obj): # 這裏的obj是循環中的書籍對象 ret = [] for author in obj.authors.all(): ret.append( {"name": author.name, "age": author.age} ) return ret
get請求數據結果:
[ { "id": 1, "publish_email": "132", "publish_name": "沙河出版社", "authors": [ { "name": "覺先生", "age": 18 }, { "name": "胡大炮", "age": 28 } ], "title": "西遊記", "price": "123.00", "publishDate": null, "publish": 1 } ]
post提交數據時,數據庫中沒有的字段,就算是提交了,也不會報錯,但是要是我們配置了某些字段,那麽在提交時,這些字段也必須有,不然會校驗失敗;
如: 我們配置了 publish_email字段,所以提交數據,要求必須有這個字段,就算提交了這個字段,數據庫也不會保存,但是不提交會校驗失敗。
RestFramework之序列化組件