1. 程式人生 > >DRF Django REST framework 之 序列化(三)

DRF Django REST framework 之 序列化(三)

Django 原生 serializer (序列化)

  1. 匯入模組  from django.core.serializers import serialize 
  2. 獲取 queryset 
  3. 對 queryset 進行序列化
  4. 將序列化之後的資料,返回給客戶端

首先,設計url, 先只定義GET和POST介面

from django.urls import path

from DrfOne import views

urlpatterns = [
    path('books/', views.BookView.as_view()),
]

再定義幾個models

 1 from django.db import models
 2 
 3 
 4 class Publish(models.Model):
 5     nid = models.AutoField(primary_key=True)
 6     name = models.CharField("出版社名", max_length=32)
 7     address = models.CharField("出版社位置", max_length=32)
 8     email = models.EmailField("郵箱")
 9 
10     def __str__(self):
11         return self.name
12 
13 
14 class Author(models.Model):
15     nid = models.AutoField(primary_key=True)
16     name = models.CharField("姓名", max_length=31)
17     age = models.IntegerField("年齡")
18 
19     def __str__(self):
20         return self.name
21 
22 
23 class Book(models.Model):
24     nid = models.AutoField(primary_key=True)
25     title = models.CharField("書名", max_length=32)
26     price = models.DecimalField("價格", max_digits=5, decimal_places=2)
27     publish = models.ForeignKey(to="Publish", on_delete=models.CASCADE)
28     authors = models.ManyToManyField(to="Author")
29 
30     def __str__(self):
31         return self.title
models.py

使用

from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView
# 1.匯入模組
from django.core.serializers import serialize


class CourseView(APIView):
    def get(self, request):
        # 2.獲取queryset    
        course_obj = models.Course.objects.all()
        # 3.序列化
        serialized_data = serialize("json", course_obj)
        print(serialized_data)
        # 4.將序列化之後的資料返回
        return HttpResponse(serialized_data)

序列化元件serializer的使用

Serializer

GET介面設計(獲取所有資料)

  1. 匯入模組
  2. 建立一個序列化類
  3. 獲取 queryset 
  4. 開始序列化
  5. 獲取序列化後的資料,返回給客戶端
from rest_framework.views import APIView
# 1.匯入模組
from rest_framework import serializers
# drf重新封裝之後的Response基於TemplateResponse型別,
# 可以將未處理的內容通過內容協商來決定返回給客戶端的正確內容形式
from rest_framework.response import Response

from DrfOne import models


# 2.建立一個序列化類,欄位名和欄位型別不一定要跟models的欄位一樣
class BookSerializer(serializers.Serializer):
    # id一般情況不用寫
    # nid = serializers.CharField(max_length=32)
    title = serializers.CharField(max_length=32)
    price = serializers.DecimalField(max_digits=5, decimal_places=2)
    # 外來鍵欄位,顯示__str__方法的返回值
    publish = serializers.CharField()

    # 多對多欄位, 執行get_欄位名 方法,手動獲取資料
    author_list = serializers.SerializerMethodField()

    def get_author_list(self, book_obj):
        # 第二個引數隨意
        author_list = list()
        for author in book_obj.authors.all():
            author_list.append(author.name)
        return author_list


class BookView1(APIView):
    def get(self, request):
        # 3.獲取queryset
        book_objs = models.Book.objects.all()
        # 4.通過序列化類進行序列化
        serialized_obj = BookSerializer(book_objs, many=True)
        # print(serialized_obj)

        # 5.獲取序列化之後的資料,返回給客戶端
        return Response(serialized_obj.data)

POST介面設計

  1. 匯入模組
  2. 建立一個序列化類
  3. 獲取客戶端請求資料
  4. 開始序列化
  5. 寫入資料庫
  6. 將插入的物件返回給客戶端

請注意,因為多對多關係欄位是我們自定義的,而且必須這樣定義,返回的資料才有意義,而使用者插入資料的時候,serializers.Serializer沒有實現create,我們必須手動插入資料,就像這樣:

# 1.匯入模組
from rest_framework import serializers
from rest_framework.views import APIView
# drf重新封裝之後的Response基於TemplateResponse型別,
# 可以將未處理的內容通過內容協商來決定返回給客戶端的正確內容形式
from rest_framework.response import Response

from DrfOne import models


# 2.建立一個序列化類,欄位名和欄位型別不一定要跟models的欄位一樣
class BookSerializer(serializers.Serializer):
    # id一般情況不用寫
    # nid = serializers.CharField(max_length=32)
    title = serializers.CharField(max_length=32)
    price = serializers.DecimalField(max_digits=5, decimal_places=2)
    # 外來鍵欄位,顯示__str__方法的返回值
    publish = serializers.CharField()
    # 僅讀欄位read_only=True,source是該欄位顯示出版社地址
    publish_address = serializers.CharField(max_length=32, read_only=True, source="publish.address")
    publish_email = serializers.CharField(max_length=32, read_only=True, source="publish.email")

    # 多對多欄位, 執行get_欄位名 方法,手動獲取資料
    author_list = serializers.SerializerMethodField()

    def get_author_list(self, book_obj):
        # 第二個引數隨意
        author_list = list()
        for author in book_obj.authors.all():
            author_list.append(author.name)
        return author_list

    def create(self, validated_data):
        # 建立時呼叫
        validated_data['publish_id'] = validated_data.pop('publish')
        book = models.Book.objects.create(**validated_data)
        return book

    def update(self, instance, validated_data):
        # 更新資料會呼叫該方法
        instance.title = validated_data.get('title', instance.title)
        instance.publishDate = validated_data.get('publishDate', instance.publishDate)
        instance.price = validated_data.get('price', instance.price)
        instance.publish_id = validated_data.get('publish', instance.publish.nid)

        instance.save()

        return instance


class BookView(APIView):
    def get(self, request):
        pass

    def post(self, request):
        # 3.獲取客戶端的資料
        client_data = request.data
        # 4.序列化,預設many=False單條資料
        verified_data = BookSerializer(data=client_data)
        # 對資料進行驗證
        if verified_data.is_valid():
            # 5.寫入資料庫
            book = verified_data.save()
            authors = models.Author.objects.filter(nid__in=request.data["authors"])
            book.authors.add(*authors)
            # 6.將插入的物件資料返回
            return Response(verified_data.data)
        # 驗證失敗返回錯誤資訊
        return Response(verified_data.errors)

從上面可以看出:

  1.  serializers.Serializer 無法插入資料,只能自己實現。
  2. 欄位太多,不能自動序列化

這樣就會非常複雜化程式,如果我希望序列化類自動插入資料呢?

這也就有了 ModelSerializer 

ModelSerializer

 ModelSerializer  類似於form元件裡的 ModelForm 

from rest_framework import serializers
from rest_framework.views import APIView


class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Book
        fields = "__all__"

        extra_kwargs = {
            # 僅寫
            "publish": {'write_only': True},
            "authors": {'write_only': True},
        }

    publish_name = serializers.CharField(max_length=32, read_only=True, source="publish.name")
    publish_address = serializers.CharField(max_length=32, read_only=True, source="publish.address")
    author_name = serializers.SerializerMethodField()

    def get_author_name(self, book_obj):
        author_list = list()
        for author in book_obj.authors.all():
            # 注意列表新增欄位,author.name而不是author
            author_list.append(author.name)
        return author_list

這樣看起來簡單多了!

get(單條資料)、put(改)、delete(刪) 介面設計

設計url

from django.urls import path, re_path

from DrfOne import views

urlpatterns = [
    path('books/', views.BookView.as_view()),
    re_path("books/(\d+)/", views.BookFilterView.as_view()),
]

檢視設計

class BookFilterView(APIView):
    def get(self, request, nid):
        # 獲取queryset
        book_obj = models.Book.objects.get(pk=nid)
        # 序列化
        serialized_data = BookSerializer(book_obj)
        # 返回資料
        return Response(serialized_data.data)

    def put(self, request, nid):
        # 獲取queryset
        book_obj = models.Book.objects.get(pk=nid)
        # 序列化, 根據instance是確認是否是更新, many預設為False可以不寫
        verified_data = BookSerializer(data=request.data, instance=book_obj, many=False)
        if verified_data.is_valid():
            verified_data.save()
            # 返回資料
            return Response(verified_data.data)
        return Response(verified_data.errors)

    def delete(self, request, nid):
        models.Book.objects.get(pk=nid).delete()

        return Response("")

~>.&