ModelSerializer序列化器實戰

HammerZe發表於2022-03-31

ModelSerializer序列化器實戰

經歷了原始碼的痛苦,掌握DRF的核心序列化器

上篇ModelSerializer序列化器做了一個小demo,演示瞭如何操作單表進行序列化和反序列化來實現五個API的使用,多表大差不差?,這裡對四個表寫五個API介面

單表操作

單表操作序列化類demo:

序列化器類

# ModelSerializer和表模型有繫結關係
class BookSerializer1(serializers.ModelSerializer):
    class Meta:
        model = Book  # 指定和哪個表有關係
        # 所有欄位
        # fields = '__all__'
        # 這裡注意id欄位是從表模型對映過來的,auto自增的,不傳也可以
        # 自定製的欄位不傳必須註冊,在列表中
        fields = ['id', 'title', 'price', 'price_info']  # 指定欄位
        extra_kwargs = {
            'title': {'write_only': True, 'max_length': 8, 'min_length': 3}
        }
    # 指定序列化的欄位:兩種寫法:在序列化類中寫;models中寫
    price_info = serializers.SerializerMethodField()
    def get_price_info(self, obj):
        return "價格是:" + str(obj.price)
    '''
    注意:自定製欄位如果和表模型獲取到的欄位是同名,那麼自定製返回給前端的欄位值就被自定製覆蓋了,比如:
    title = serializers.SerializerMethodField()
    def get_title(self, obj):
        return "書名是:" + str(obj.title)
    '''

    #  區域性和全域性鉤子,跟之前一樣,但是要注意寫在Meta外

檢視類

from rest_framework.views import APIView
from .models import Book
from rest_framework.response import Response
from app01.serializer import  BookSerializer1
class BookView1(APIView):
    def get(self, request):
        # 從資料庫查資料,做序列化
        book_list = Book.objects.all()
        # 例項化類,傳入初始化的引數,instance和many
        '''
        instance:要序列化的物件  qs,單個物件
        many:如果是qs物件,many=True,如果是單個物件many=False
        '''
        ser = BookSerializer1(instance=book_list, many=True)
        # ser.data使用模型類的物件得到序列化後的字典
        return Response(ser.data)

    def post(self,request):
        # 反序列化,儲存到資料庫使用data引數
        deser = BookSerializer1(data=request.data)
        # 校驗資料
        if deser.is_valid():
            # 儲存需要重寫create方法,不然不知道存到哪個表
            deser.save()
            return Response(deser.data)
        return Response({'code':101,'msg':'校驗不通過','errors':deser.errors})



# 處理修改再寫一個檢視類,防止get衝突
class BookDetailView1(APIView):
    def get(self,request,pk):
        book = Book.objects.filter(pk=pk).first()
        ser = BookSerializer1(instance=book)  # 這裡設定了主鍵值,單條記錄many不需要寫
        return Response(ser.data)
    def delete(self,request,pk):
        res = Book.objects.filter(pk=pk).delete()
        print(res) # (1, {'app01.Book': 1})
        # res是影響的行數
        if res[0]>0:
            return Response({'code': 100, 'msg': '刪除成功'})
        else:
            return  Response({'code': 103, 'msg': '要刪除的資料不存在'})

    # 反序列化修改
    def put(self,request,pk):
        # 修改處理單條資料用過pk確定求改哪條資料
        book = Book.objects.filter(pk=pk).first()
        # 序列化器類例項化需要傳入instance,data才表示修改
        ser = BookSerializer1(instance=book,data=request.data)
        if ser.is_valid():
            # 重寫update方法才能存入
            ser.save()
            return Response(ser.data)
        return Response({'code':101,'msg':'校驗未通過','error':ser.errors})

路由

path('books1/', views.BookView1.as_view()),
path('books1/<int:pk>', views.BookDetailView1.as_view()),

模型

from django.db import models
class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5,decimal_places=2)
    authors = models.CharField(max_length=32)

多表操作

models.py

from django.db import models



# build four model tables

class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.DecimalField(decimal_places=2, max_digits=5)
    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
    authors = models.ManyToManyField(to='Author')

    def __str__(self):
        return self.name

    # 自定製欄位
    @property
    def publish_detail(self):
        return {'name': self.publish.name, 'addr': self.publish.city}

    @property
    def author_list(self):
        l = []
        print(self.authors.all()) # <QuerySet [<Author: Author object (1)>, <Author: Author object (2)>]>
        for author in self.authors.all():
            print(author.author_detail) # AuthorDetail object (1)
            l.append({'name': author.name, 'age': author.age, 'addr': author.author_detail.addr})
        return l


class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)

    def __str__(self):
        return self.name

    @property
    def authordetail_info(self):
        return {'phone':self.author_detail.telephone,'addr':self.author_detail.addr}


class AuthorDetail(models.Model):
    telephone = models.BigIntegerField()
    addr = models.CharField(max_length=64)


class Publish(models.Model):
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=32)
    email = models.EmailField()

serializer.py

from app01 import models
from rest_framework import serializers


# 書序列化器
class BookSerializer(serializers.ModelSerializer):
    class Meta:
        # 指定和哪個表有關係
        model = models.Book
        # fields = '__all__'
        fields = ['id','name','price','publish','authors','publish_detail','author_list']
        # 將關聯表的資訊全部取出來,不推薦使用
        # depth = 1

        extra_kwargs = {
            'publish':{'write_only':True},
            'authors':{'write_only':True}
        }

# 作者序列化器
class AuthorSerializer(serializers.ModelSerializer):
    class Meta:
        # 指定和哪個表有關係
        model = models.Author
        # fields = '__all__'
        fields = ['id', 'name', 'age', 'author_detail', 'authordetail_info']
        extra_kwargs = {
            'author_detail': {'write_only': True},
        }


# 作者詳情序列化器
class AuthorDetailSerializer(serializers.ModelSerializer):
    class Meta:
        # 指定和哪個表有關係
        model = models.AuthorDetail
        fields = '__all__'

# 出版社序列化器
class PublishSerializer(serializers.ModelSerializer):
    class Meta:
        # 指定和哪個表有關係
        model = models.Publish
        fields = '__all__'

views.py

from rest_framework.response import Response
from rest_framework.views import APIView

from app01 import models
from app01 import serializer


# 書檢視類
class BookView(APIView):
    def get(self, requets):
        # 序列化
        book_list = models.Book.objects.all()
        # 序列化多條資料many=True
        ser = serializer.BookSerializer(instance=book_list, many=True)
        return Response(ser.data)

    def post(self, request):
        # 獲取反序列化資料
        ser = serializer.BookSerializer(data=request.data)
        if ser.is_valid():
            # 校驗通過存入資料庫,不需要重寫create方法了
            ser.save()
            return Response({'code': 100, 'msg': '新增成功', 'data': ser.data})
        # 校驗失敗
        return Response({'code': 101, 'msg': '校驗未通過', 'error': ser.errors})


class BookViewDetail(APIView):
    def get(self, request, pk):
        book = models.Book.objects.filter(pk=pk).first()
        ser = serializer.BookSerializer(instance=book)
        return Response(ser.data)

    def put(self, request, pk):
        book = models.Book.objects.filter(pk=pk).first()
        # 修改,instance和data都要傳
        ser = serializer.BookSerializer(instance=book, data=request.data)
        if ser.is_valid():
            # 校驗通過修改,不需要重寫update
            ser.save()
            return Response({'code:': 100, 'msg': '修改成功', 'data': ser.data})
        # 校驗不通過
        return Response({'code:': 102, 'msg': '校驗未通過,修改失敗', 'error': ser.errors})

    def delete(self, request, pk):
        models.Book.objects.filter(pk=pk).delete()
        return Response({'code': 100, 'msg': '刪除成功'})


# 作者檢視類
class AuthorView(APIView):
    def get(self, requets):
        # 序列化
        author_list = models.Author.objects.all()
        # 序列化多條資料many=True
        ser = serializer.AuthorSerializer(instance=author_list, many=True)
        return Response(ser.data)

    def post(self, request):
        # 獲取反序列化資料
        ser = serializer.AuthorSerializer(data=request.data)
        if ser.is_valid():
            # 校驗通過存入資料庫,不需要重寫create方法了
            ser.save()
            return Response({'code': 100, 'msg': '新增成功', 'data': ser.data})
        # 校驗失敗
        return Response({'code': 101, 'msg': '校驗未通過', 'error': ser.errors})


class AuthorViewDetail(APIView):
    def get(self, request, pk):
        book = models.Author.objects.filter(pk=pk).first()
        ser = serializer.AuthorSerializer(instance=book)
        return Response(ser.data)

    def put(self, request, pk):
        book = models.Author.objects.filter(pk=pk).first()
        # 修改,instance和data都要傳
        ser = serializer.AuthorSerializer(instance=book, data=request.data)
        if ser.is_valid():
            # 校驗通過修改,不需要重寫update
            ser.save()
            return Response({'code:': 100, 'msg': '修改成功', 'data': ser.data})
        # 校驗不通過
        return Response({'code:': 102, 'msg': '校驗未通過,修改失敗', 'error': ser.errors})

    def delete(self, request, pk):
        models.Author.objects.filter(pk=pk).delete()
        return Response({'code': 100, 'msg': '刪除成功'})


# 作者詳情檢視類
class AuthorDetailView(APIView):
    def get(self, requets):
        # 序列化
        author_list = models.AuthorDetail.objects.all()
        # 序列化多條資料many=True
        ser = serializer.AuthorDetailSerializer(instance=author_list, many=True)
        return Response(ser.data)

    def post(self, request):
        # 獲取反序列化資料
        ser = serializer.AuthorDetailSerializer(data=request.data)
        if ser.is_valid():
            # 校驗通過存入資料庫,不需要重寫create方法了
            ser.save()
            return Response({'code': 100, 'msg': '新增成功', 'data': ser.data})
        # 校驗失敗
        return Response({'code': 101, 'msg': '校驗未通過', 'error': ser.errors})


class OneAuthorViewDetail(APIView):
    def get(self, request, pk):
        book = models.AuthorDetail.objects.filter(pk=pk).first()
        ser = serializer.AuthorDetailSerializer(instance=book)
        return Response(ser.data)

    def put(self, request, pk):
        book = models.AuthorDetail.objects.filter(pk=pk).first()
        # 修改,instance和data都要傳
        ser = serializer.AuthorDetailSerializer(instance=book, data=request.data)
        if ser.is_valid():
            # 校驗通過修改,不需要重寫update
            ser.save()
            return Response({'code:': 100, 'msg': '修改成功', 'data': ser.data})
        # 校驗不通過
        return Response({'code:': 102, 'msg': '校驗未通過,修改失敗', 'error': ser.errors})

    def delete(self, request, pk):
        models.AuthorDetail.objects.filter(pk=pk).delete()
        return Response({'code': 100, 'msg': '刪除成功'})

# 出版社檢視類
class PublishView(APIView):
    def get(self, requets):
        # 序列化
        author_list = models.Publish.objects.all()
        # 序列化多條資料many=True
        ser = serializer.PublishSerializer(instance=author_list, many=True)
        return Response(ser.data)

    def post(self, request):
        # 獲取反序列化資料
        ser = serializer.PublishSerializer(data=request.data)
        if ser.is_valid():
            # 校驗通過存入資料庫,不需要重寫create方法了
            ser.save()
            return Response({'code': 100, 'msg': '新增成功', 'data': ser.data})
        # 校驗失敗
        return Response({'code': 101, 'msg': '校驗未通過', 'error': ser.errors})


class PublishViewDetail(APIView):
    def get(self, request, pk):
        book = models.Publish.objects.filter(pk=pk).first()
        ser = serializer.PublishSerializer(instance=book)
        return Response(ser.data)

    def put(self, request, pk):
        book = models.Publish.objects.filter(pk=pk).first()
        # 修改,instance和data都要傳
        ser = serializer.PublishSerializer(instance=book, data=request.data)
        if ser.is_valid():
            # 校驗通過修改,不需要重寫update
            ser.save()
            return Response({'code:': 100, 'msg': '修改成功', 'data': ser.data})
        # 校驗不通過
        return Response({'code:': 102, 'msg': '校驗未通過,修改失敗', 'error': ser.errors})

    def delete(self, request, pk):
        models.Publish.objects.filter(pk=pk).delete()
        return Response({'code': 100, 'msg': '刪除成功'})

urls.py

from django.contrib import admin
from django.urls import path

from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    # 書
    path('books/', views.BookView.as_view()),
    path('books/<int:pk>', views.BookViewDetail.as_view()),

    # 作者
    path('authors/', views.AuthorView.as_view()),
    path('authors/<int:pk>', views.AuthorViewDetail.as_view()),

    # 作者詳情
    path('authorsdetail/', views.AuthorDetailView.as_view()),
    path('authorsdetail/<int:pk>', views.OneAuthorViewDetail.as_view()),

    # 出版社
    path('publish/', views.PublishView.as_view()),
    path('publishdetail/<int:pk>', views.PublishViewDetail.as_view()),
]

image

Postman自行測試,我測了測都能用,有問題望指正~

相關文章