1. 程式人生 > 其它 >11 多表關聯的序列化和反序列化

11 多表關聯的序列化和反序列化

1.模型類序列化器ModelSerializer

publish單表基於ModelSerializer寫的5個介面

models.py

from django.db import models


#### 圖書表   出版社   作者   作者詳情    圖書和作者的多對多表

# 一對多:關係一旦確立,關係欄位寫在多的一方
# 多對多:需要有中間表

class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    
# on_delete: # models.CASCADE # 級聯刪除 # models.DO_NOTHING # 什麼都不做 # models.SET_DEFAULT # 設定為預設值 # models.SET_NULL # 設定為空 # models.SET # 可以寫一個函式記憶體地址,刪除的時候,觸發這個函式執行 publish = models.ForeignKey(to='Publish', on_delete=models.SET_NULL, null=True) authors = models.ManyToManyField(to='
Author') class Publish(models.Model): name = models.CharField(max_length=16) address = models.CharField(max_length=64) class Author(models.Model): name = models.CharField(max_length=16) sex = models.IntegerField(choices=[(0, ''), (1, '')], default=0) class AuthorDetail(models.Model): mobile
= models.CharField(max_length=11) author = models.OneToOneField(to='Author', on_delete=models.CASCADE) # OneToOneField 本質就是 ForeignKey+unique

urls.py

from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
    path('admin/', admin.site.urls),
    path('publish/',views.PublishView.as_view()),
    path('publish/<int:pk>',views.PublishDetailView.as_view()),
]

views.py

from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Publish
from .seriazlizer import PublishSerializer


class PublishView(APIView):
    def get(self, request):
        publish_list = Publish.objects.all()
        ser = PublishSerializer(instance=publish_list, many=True)
        return Response(data=ser.data)

    def post(self, request):
        ser = PublishSerializer(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response(ser.data)
        else:
            return Response(ser.errors)
        # ser.is_valid(raise_exception=True)


class PublishDetailView(APIView):
    def get(self, request, pk):
        publish = Publish.objects.all().filter(pk=pk).first()
        ser = PublishSerializer(instance=publish)
        return Response(data=ser.data)

    def put(self, request, pk):
        publish = Publish.objects.all().filter(pk=pk).first()    # 資料不存在 ,None,如果instance是None,ser.save -->是新增
        ser = PublishSerializer(data=request.data, instance=publish)
        if ser.is_valid():
            ser.save()
            return Response(ser.data)
        else:
            return Response(ser.errors)
        # ser.is_valid(raise_exception=True)

    def delete(self, request, pk):
        res = Publish.objects.all().filter(pk=pk).delete()  # 返回影響的行數
        if res >= 1:
            return Response()
        else:
            return Response('要刪除的資料不存在')

serializer.py(模型類序列化器ModelSerializer)

class PublishSerializer(serializers.ModelSerializer):
    class Meta:
        model = Publish
        fields = "__all__"

publish單表通過postman操作post,get,put,delete

2,圖書的多表關聯的序列化和反序列化的5個介面

views.py

############# 圖書的多表關聯的5個介面
from .models import Book, AuthorDetail, Author
from .seriazlizer import BookSerializer


class BookView(APIView):
    def get(self, request):
        book_list = Book.objects.all()
        ser = BookSerializer(instance=book_list, many=True)
        return Response(data=ser.data)

    def post(self, request):
        ser = BookSerializer(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response(ser.data)
        else:
            return Response(ser.errors)
        # ser.is_valid(raise_exception=True)


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

    def put(self, request, pk):
        book = Book.objects.all().filter(pk=pk).first()  # 資料不存在 ,None,如果instance是None,ser.save -->是新增
        ser = BookSerializer(data=request.data, instance=book)
        if ser.is_valid():
            ser.save()
            return Response(ser.data)
        else:
            return Response(ser.errors)
        # ser.is_valid(raise_exception=True)

    def delete(self, request, pk):
        res = Book.objects.all().filter(pk=pk).delete()  # 返回影響的行數
        if res >= 1:
            return Response()
        else:
            return Response('要刪除的資料不存在')

urls.py

from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
    path('admin/', admin.site.urls),
    path('book/', views.BookView.as_view()),
    path('book/<int:pk>', views.BookDetailView.as_view()),
]

方式一:在表模型中寫方法,在序列化類的fields宣告一下就可以

models.py

from django.db import models


class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    # on_delete:
    # models.CASCADE   # 級聯刪除
    # models.DO_NOTHING  # 什麼都不做
    # models.SET_DEFAULT  # 設定為預設值
    # models.SET_NULL  # 設定為空
    # models.SET   # 可以寫一個函式記憶體地址,刪除的時候,觸發這個函式執行
    publish = models.ForeignKey(to='Publish', on_delete=models.SET_NULL, null=True)
    authors = models.ManyToManyField(to='Author')

    @property  # 加不加都行
    def publish_detail(self):
        return {'name':self.publish.name,'address':self.publish.address}

    # 作者詳情 在列表套字典
    def author_detail(self):
        # 獲取所有的作者
        author_list=self.authors.all()
        author_dict_list = []
        for author in author_list:
            author_dict_list.append({'name':author.name,'sex':author.get_sex_display()})
        return author_dict_list

serializers.py

from rest_framework import serializers
from .models import Book, Publish, Author, AuthorDetail


class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ['id','title','price','publish','authors','publish_detail','author_detail'] # 欄位可是屬性,也可以是方法
        # depth=1  # 深度查一層,官方建議不大於10,正常不超過3,不建議用
        extra_kwargs={'publish':{'write_only':True},
                      'author':{'write_only':True},
                      'publish_detail':{'read_only':True},
                      'author_detail':{'read_only':True}
                      }

    # 只顯示publish的出版社名字和地址
    # 方式一:在表模型中寫方法,在序列化類的fields宣告一下就可以

圖書的多表通過Postman關聯的序列化和反序列化

方法二:在序列化類中寫

serializer.py

from rest_framework import serializers
from .models import Book, Publish, Author, AuthorDetail
class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        # 寫在BookSerializer的類屬性,也需要在fields中註冊一下
        fields = ['id', 'title', 'price', 'publish', 'authors','publish_detail','author_detail']  # 欄位可是屬性,也可以是方法
        # depth=1  # 深度查一層,官方建議不大於10,正常不超過3,不建議用
        extra_kwargs = {'publish': {'write_only': True},
                        'author': {'write_only': True},
                        }
    # 只顯示publish的出版社名字和地址
    # 方法二: 在序列化類中寫
    publish_detail = serializers.SerializerMethodField(read_only=True)  # 這欄位需要配合一個方法,方法必須叫get_欄位名,方法返回什麼,publish_detail

    def get_publish_detail(self, obj):
        # obj就是當前序列化到的物件,就是book物件
        return {'name': obj.publish.name, 'address': obj.publish.address}

    author_detail=serializers.SerializerMethodField(read_only=True)
    def get_author_detail(self,obj):
        author_list = self.authors.all()
        author_dict_list = []
        for author in author_list:
            author_dict_list.append({'name': author.name, 'sex': author.get_sex_display()})
        return author_dict_list

圖書的多表通過Postman關聯的序列化和反序列化

方式三:通過子序列化

serializer.py

class BookSerializer(serializers.ModelSerializer):
    publish = PublishSerializer()
    authors = AuthorSerializer(many=True)  # 多條,一定要加一個 many=True
    class Meta:
        model = Book
        # 寫在BookSerializer的類屬性,也需要在fields中註冊一下
        fields = ['id', 'title', 'price', 'publish', 'authors']  # 欄位可以是屬性,也可以是方法(是方法返回值)
        # depth=1  # 深度查一層,官方建議不大於10,正常不超過3,不建議用
        extra_kwargs = {'publish': {'write_only': True},
                        'authors': {'write_only': True},
                        }

注意:其他的幾個檔案都不變

圖書的多表通過Postman關聯的序列化和反序列化