1. 程式人生 > >RestFramework之序列化組件

RestFramework之序列化組件

efi 格式 過程 framework length serialize 意義 emp for

一,自己手動序列化

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之序列化組件