数据库之间互相关联,一对多和多对多,继承ModelSerializer的序列化器内部代码需要定制
为了多对多关联,我们同时使用自动多对多建立了editor和book的关系,
半自动多对多建立了author和book的关系
# models.py文件
# models.py
from django.db import models
# Create your models here.
# 创建表book,author,publish
# publish和book是一对多的关系,外键在book表
# author和book是多对多的关系,外键在book中,手动创建了第三张表book2author表示二者对应关系
class Book(models.Model):
title = models.CharField(max_length=255, verbose_name="书名")
price = models.IntegerField(verbose_name="价格")
# publish和book 一对多关系 外键设在多的book表内
publish = models.ForeignKey(to="Publish", on_delete=models.CASCADE)
# 采用半自动方式建立author和book表之间的多对多关系
authors = models.ManyToManyField(to="Author",
through="Book2Author",
through_fields=('book','author')
)
# 采用全自动方式建立editor和book表之间的多对多关系
editors = models.ManyToManyField(to="Editor")
class Meta:
db_table = "bookstore_book"
verbose_name = "书籍"
verbose_name_plural = verbose_name
def __str__(self):
return self.title
# editor表,和book多对多
class Editor(models.Model):
name = models.CharField(max_length=255,verbose_name="主编姓名")
class Meta:
db_table = "bookstore_editor"
verbose_name = "主编"
verbose_name_plural = verbose_name
def __str__(self):
return self.name
class Publish(models.Model):
name = models.CharField(max_length=255, verbose_name="出版社名称")
addr = models.CharField(max_length=255, verbose_name="出版社地址")
class Meta:
db_table = "bookstore_publish"
verbose_name = "出版社"
verbose_name_plural = verbose_name
def __str__(self):
return self.name
# author表,和book表多对多
class Author(models.Model):
name = models.CharField(max_length=255, verbose_name="作者姓名")
class Meta:
db_table = "bookstore_author"
verbose_name = "作者"
verbose_name_plural = verbose_name
def __str__(self):
return self.name
# 半自动创建一个book和author的多对多关系表
# 和前面自动创建的book和editor的多对多关系表形成对比
class Book2Author(models.Model):
book = models.ForeignKey(to="Book", on_delete=models.CASCADE)
author = models.ForeignKey(to="Author", on_delete=models.CASCADE)
class Meta:
db_table = "bookstore_book2author"
verbose_name = "书籍作者关系表"
verbose_name_plural = verbose_name
为了测试序列化和反序列化在使用ModelSerializer组件时的方法,我们从序列化GET请求和反序列化POST请求来分析
# serializers.py文件
# serializers.py
from rest_framework import serializers
from bookstore import models
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = "__all__"
# depth = 1
class EditorModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Editor
fields = "__all__"
class PublishModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Publish
fields = "__all__"
class AuthorModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Author
fields = "__all__"
class Book2AuthorModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Book2Author
fields = "__all__"
# views.py文件
# views.py
from rest_framework.viewsets import ModelViewSet
from bookstore import models
from bookstore import serializers
# Create your views here.
class BookModelViewSet(ModelViewSet):
queryset = models.Book.objects.all()
serializer_class = serializers.BookModelSerializer
class EditorModelViewSet(ModelViewSet):
queryset = models.Editor.objects.all()
serializer_class = serializers.EditorModelSerializer
class PublishModelViewSet(ModelViewSet):
queryset = models.Publish.objects.all()
serializer_class = serializers.PublishModelSerializer
class AuthorModelViewSet(ModelViewSet):
queryset = models.Author.objects.all()
serializer_class = serializers.AuthorModelSerializer
class Book2AuthorModelViewSet(ModelViewSet):
queryset = models.Book2Author.objects.all()
serializer_class = serializers.Book2AuthorModelSerializer
完成models.py , serializers.py , views.py三个文件,我们使用Postman来测试GET请求和POST请求
一 GET请求
# 左侧为book列表,为列表套字典,右侧为单本书的详细信息,为字典格式
# 自动创建的多对多editors和半自动创建的authors都能够正确显示
# 但是,结果中并没有显示外键字段的详细信息,比如我同事需要authors,editors的姓名,id等信息
# 修改序列化器中的序列化深度depth属性=1就可以显示
# serializers.py
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = "__all__"
depth = 1
# 序列化深度depth属性能够将关联属性的表属性也显示序列化出来
# 引用序列化深度depth属性的字段序列化时会自动变为readonly,所以更新或创建时,不能使用该序列化器类
可以看出不管是自动化创建的多对多关系,还是半自动创建的多对多关系,以及一对多关系,此时都能够正确的在序列化信息显示.
但是,一旦使用了含有序列化深度depth属性的序列化器,那么引用改属性的字段就无法进行更新或者创建
如果不使用深度属性depth,有另外一种方法也可以得到多层序列化信息,如下
# serializers.py
class BookModelSerializer(serializers.ModelSerializer):
publish = PublishModelSerializer()
# 如果有多条,就many=True
editors = EditorModelSerializer(many=True)
authors = AuthorModelSerializer(many=True)
class Meta:
model = models.Book
fields = "__all__"
# depth = 1
二 POST请求
因此,我们可以采用将GET请求和POST请求分开使用不同的序列化器的方式来解决这个问题.
# serializers.py文件
将BookModelSerializer分拆为右边的GetModelSerializer,PostModelSerializer两个类
| ==> |
|
# views.py文件
# view.py
class BookModelViewSet(ModelViewSet):
queryset = models.Book.objects.all()
# serializer_class = serializers.BookModelSerializer
def get_serializer_class(self): # 重写了基类里面的get_serializer_class方法,这是固定写法
serializer_class = self.serializer_class
if self.request.method in ['PUT','POST','PATCH']:
serializers_class = serializers.PostModelSerializer
if self.request.method == 'GET':
serializers_class = serializers.GetModelSerializer
return serializers_class
如此,GET请求能够得到包括关联表的详细序列化信息,同时POST请求可以同时将数据添加到一对多关联表,以及自动创建的多对多关联表中,半自动创建的多对多关联表无法更新.
注意:
# 半自动创建的多对多关联表无法更新
# 无法同时添加多个值,比如一本书可以同时有多个主编,但是添加时,数据无法同时更新多个主编
另外同时满足一对多,多对多创建更新的方法:重写create方法和update方法:
class BookModelSerializer(serializers.ModelSerializer):
# 嵌套序列化信息
editors = EditorModelSerializer(many=True)
authors = AuthorModelSerializer(many=True)
publish = PublishModelSerializer()
class Meta:
model = models.Book
fields = "__all__"
def create(self, validated_data):
editors_data = validated_data.pop('editors')
authors_data = validated_data.pop('authors')
publish_data = validated_data.pop('publish')
publish = models.Publish.objects.get(name=publish_data.get('name'))
# 用fliter就是queryset,用get才是对象instance或obj
# 添加一对多数据,和orm用法一致
book = models.Book.objects.create(**validated_data,publish=publish)
# 添加多对多字段数据,同样和orm用法一致
for editor_data in editors_data:
editor = models.Editor.objects.get(name=editor_data.get('name'))
book.editors.add(editor)
# 添加多对多字段数据,此处是半自动创建的多对多,无法使用add方法,用orm的create方法
for author_data in authors_data:
author = models.Author.objects.get(name=author_data.get('name'))
models.Book2Author.objects.create(book=book,author=author)
return book
三 反向查找并序列化 _set
上述一对多,多对多序列化我们是从外键所在的表正向查找另外的表的数据,再进行序列化
如果我们想从一对多的一的一方反向查找多的一方并序列化,或者从多对多的非外键所在表反向查找,
如下:
# editor表和book表示多对多,外键在book表中
# publish表和book表示一对多,外键在book表中
class EditorModelSerializer(serializers.ModelSerializer):
# 反向查找
book_set = serializers.StringRelatedField(many=True,read_only=True)
# book_set = serializers.PrimaryKeyRelatedField(many=True,read_only=True)
class Meta:
model = models.Editor
# fields = ['name']
fields = "__all__"
class PublishModelSerializer(serializers.ModelSerializer):
# 反向查询
# book_set = serializers.StringRelatedField(many=True,read_only=True)
book_set = serializers.PrimaryKeyRelatedField(many=True,read_only=True)
class Meta:
model = models.Publish
fields = "__all__"
class AuthorModelSerializer(serializers.ModelSerializer):
# 反向查询
book_set = serializers.PrimaryKeyRelatedField(many=True,read_only=True)
class Meta:
model = models.Author
fields = "__all__"
# 使用orm语法的标识:"表名_set"即可反向查找
# 对自动创建的多对多和半自动创建的多对多同样适用