drf-多表关联序列化和反序列化

发布时间 2023-09-02 17:04:09作者: Way*yy

反序列化之updata

视图层

class AddBookView(APIView):
    def put(self, request, pk):
        book_obj = models.Book.objects.filter(pk=pk).first()
        book = BookSerializer(book_obj, data=request.data)
        if book.is_valid():
            book.save()
            return Response({"code": 200, "msg": book.data})
        else:
            return Response({"code": 101, "msg": book.errors})

序列化

重写updata方法:
def update(self, instance, validated_data):
    models.Book.objects.filter(pk=instance.pk).update(**validated_data)
    return instance

source的高级用法

字段类中的属性,作用是能修改序列化的字段


方式一:
    class BookSerializer(serializers.Serializer):
        wayyy = serializers.CharField(source="book_name")
        
	前端接收到的:
    {
        "wayyy": "西游记",
    },
    
方法二:跨表查询
	序列化:
    class BookSerializer(serializers.Serializer):
        publish_id = serializers.CharField(source="publish.publish_name")
	
	前端接收到的:
    {
        "publish_id": "东京出版社"
    },
    
方式三:表模型中写方法,在序列化层拿到返回的名字
	序列化:
    class BookSerializer(serializers.Serializer):
    	xxx = serializers.CharField(source="get_name")
	models层:
    def get_name(self):
        return self.publish.publish_name
	前端接收到的:
    {
        "wayyy": "西游记",
        "book_price": 500,
        "xxx": "东京出版社"
    }

高级用法定制字段

定制返回的字段格式,一共有三种格式ps(publish也是一个对象)   
    {
        "book_name": "西游记",
        "book_price": 500,
        "publish": {
            "publish_name": "东京出版社",
            "publish_addr": "东京"
        }
    },
    
    
第一种:在序列化类使用SerializerMethodField 定制
    class BookSerializer(serializers.Serializer):
        publish = serializers.SerializerMethodField()

        def get_publish(self, obj):# 返回什么,序列化后publish就是什么
            # obj就是序列化得到的book对象
            return {"publish_name": obj.publish.publish_name, "publish_addr": obj.publish.publish_addr}
        
第二种:在表模型中定制
	models:
    # 将方法伪装成属性
    @property
    def publish_dic(self):
        return {"publish_name": self.publish.publish_name, "publish_addr": self.publish.publish_addr}
    序列化类:
    	publish_dic = serializers.DictField()

多表关联序列化和反序列化

# 多表关联序列化和反序列化,要分清楚哪些字段是需要序列化,哪些字段是需要反序列化,哪些字段是即需要序列化又需要反序列化

序列化

from rest_framework import serializers
from app_one import models


class BookSerializer(serializers.Serializer):
    # 这两个字段是既要序列化又要反序列化
    book_name = serializers.CharField(max_length=8, min_length=1, )
    book_price = serializers.IntegerField(max_value=1000, min_value=10)
    
    # 这两个字段只需要序列化:将我自己的数据序列化传给前端
    publish_dic = serializers.DictField(read_only=True)
    author_list = serializers.ListField(read_only=True)
    
    # 这两个字段需要反序列化:反序列化就是将前端传过来的数据进行处理转换成我自己数据
    publish_id = serializers.CharField(write_only=True)
    author_book = serializers.ListField(write_only=True)

    # def validate_book_name(self, value):
    #     pass
    #
    # def validate(self, attrs):
    #     pass

    def create(self, validated_data):
        authors = validated_data.pop("author_book")
        book_data = models.Book.objects.create(**validated_data)
        # 增加中间表的记录:图书和作者的关系
        book_data.authors.add(*authors)# 向中间表中存入:这个图书关联的做作者
        return book_data

    def update(self, instance, validated_data):
        models.Book.objects.filter(pk=instance.pk).update(**validated_data)
        return instance

针对返回的数据格式在models层做的处理

class Book(models.Model):
    book_name = models.CharField(max_length=32)
    book_price = models.IntegerField()
    is_delete = models.IntegerField(default=0)

    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)

    authors = models.ManyToManyField(to='Author')

    @property
    def publish_dic(self):
        # 出版社的返回信息必须是以字典形式返回
        return {"publish_name": self.publish.publish_name, "publish_addr": self.publish.publish_addr}

    @property
    def author_list(self):
        # 图书作者的返回信息以列表形式展现
        lis = []
        for author in self.authors.all():
            lis.append({"author_name": author.username})
        return lis

视图层

from django.shortcuts import render
from rest_framework.views import APIView
from .serializers import BookSerializer
from rest_framework.response import Response
from app_one import models


# Create your views here.


class BookView(APIView):

    def get(self, request):
        book_obj = models.Book.objects.filter(is_delete=0).all()
        book = BookSerializer(instance=book_obj, many=True)
        return Response(book.data)

    def post(self, request):
        print(request.data)
        book = BookSerializer(data=request.data)
        if book.is_valid():
            book.save()
            return Response({"code": 100, "msg": book.data})
        else:
            return Response({"code": 101, "msg": book.errors})


class AddBookView(APIView):
    def get(self, request, pk):
        book_obj = models.Book.objects.filter(pk=pk).filter()
        book = BookSerializer(instance=book_obj)
        return Response(book.data)

    def put(self, request, pk):
        book_obj = models.Book.objects.filter(pk=pk).first()
        book = BookSerializer(book_obj, data=request.data)
        if book.is_valid():
            book.save()
            return Response({"code": 200, "msg": book.data})
        else:
            return Response({"code": 101, "msg": book.errors})

    def delete(self, request, pk):
        models.Book.objects.filter(pk=pk).update(is_delete=1)
        return Response({"code": 200, "msg": "删除成功"})

路由层

from django.contrib import admin
from django.urls import path
from app_one.views import BookView, AddBookView

urlpatterns = [
    path('admin/', admin.site.urls),

    path('books/', BookView.as_view()),

    path('books/<int:pk>/', AddBookView.as_view()),
]

多表查询序列化及反序列化总结

1、使用之前必须先判断清除哪些字段是用来序列化的,哪些字段是用来反序列化,哪些字段是用来即序列化又反序列化的
	1.1、判断完成以后,在只需要序列化的字段里加入参数read_only=True表示该字段仅用于序列化
    1.2、在只需要反序列化的字段里加入参数write_only=True表示该字段仅用于反序列化
    1.3、如果这两个参数都没写,表示该字段既用于序列化又用于反序列化
2、确定返回给前端的数据是返回什么样的格式,需不需要自定义字段
	2.1、在models层自定义字段的时候,方法名要和字段名保持一致
    2.2、如果在序列化类里面写定制字段,注意方法名的命名 get_要定制的字段
    2.3、在序列化类中定制要使用serializers.SerializerMethodField()
    2.4、在models定制返回的如果是字典,序列化类里面定制的字段要用serializers.DictField,如果返回的是列表,要使用erializers.ListField
    
3、做反序列化校验
	# 三层:
	字段自己:字段类属性--->可控制的比较小
    局部钩子:单个字段校验---->校验反序列化的字段
    全局钩子:多个字段同时校验

作业

# 1 图书表,作者表,出版社表
	-5个接口都写
    
# 2 创建出作者和作者详情表
	-新增一个作者和作者详情--->一次性提交过来
    
    
# 拓展:
	# 新增传这种数据过来,新增图书,新增一个作者,新增一个出版社
	{"name":"新西游记111","price":199,"publish_id":{name:西安出版社,addr:西安},"authors":[{"name": "lqz","sex": "男","age": 19}]}

1 图书表,作者表,出版社表-5个接口都写

序列化

from rest_framework import serializers
from app_one import models


class BookSerializer(serializers.Serializer):
    # 这两个字段是既要序列化又要反序列化
    book_name = serializers.CharField(max_length=8, min_length=1, )
    book_price = serializers.IntegerField(max_value=1000, min_value=10)
    # 这两个字段只需要序列化:将我自己的数据序列化传给前端
    publish_dic = serializers.DictField(read_only=True)
    author_list = serializers.ListField(read_only=True)
    # 这两个字段需要反序列化:反序列化就是将前端传过来的数据进行处理转换成我自己数据
    publish_id = serializers.CharField(write_only=True)
    author_book = serializers.ListField(write_only=True)

    # def validate_book_name(self, value):
    #     pass
    #
    # def validate(self, attrs):
    #     pass

    def create(self, validated_data):
        authors = validated_data.pop("author_book")
        book_data = models.Book.objects.create(**validated_data)
        book_data.authors.add(*authors)
        return book_data
	# 重写updata方法
    def update(self, instance, validated_data):
        author_book = validated_data.pop("author_book")
        models.Book.objects.filter(pk=instance.pk).update(**validated_data)
        instance.authors.add(*author_book)
        return instance

视图类

from django.shortcuts import render
from rest_framework.views import APIView
from .serializers import BookSerializer
from rest_framework.response import Response
from app_one import models


# Create your views here.


class BookView(APIView):

    def get(self, request):
        book_obj = models.Book.objects.filter(is_delete=0).all()
        book = BookSerializer(instance=book_obj, many=True)
        return Response(book.data)

    def post(self, request):
        print(request.data)
        book = BookSerializer(data=request.data)
        if book.is_valid():
            book.save()
            return Response({"code": 100, "msg": book.data})
        else:
            return Response({"code": 101, "msg": book.errors})


class AddBookView(APIView):
    def get(self, request, pk):
        book_obj = models.Book.objects.filter(pk=pk).filter()
        # 这个地方拿到的是QuerySet对象[book_obj对象]
        book = BookSerializer(instance=book_obj[0])
        return Response(book.data)

    def put(self, request, pk):
        book_obj = models.Book.objects.filter(pk=pk).first()
        book = BookSerializer(book_obj, data=request.data)
        if book.is_valid():
            book.save()
            return Response({"code": 200, "msg": book.data})
        else:
            return Response({"code": 101, "msg": book.errors})

    def delete(self, request, pk):
        models.Book.objects.filter(pk=pk).update(is_delete=1)
        return Response({"code": 200, "msg": "删除成功"})

2 创建出作者和作者详情表,-新增一个作者和作者详情--->一次性提交过来

序列化类

class AuthorSerializer(serializers.Serializer):
    username = serializers.CharField(max_length=8, min_length=3)
    age = serializers.IntegerField()
    gender = serializers.CharField(max_length=3, min_length=1)
    addr = serializers.CharField(max_length=8, min_length=2)

    def create(self, validated_data):
        username = validated_data.pop("username")
        print("+++++++", validated_data)
        author_detail = models.AuthorDetail.objects.create(**validated_data)
        authors = models.Author.objects.create(username=username, detail_id=author_detail.pk)
        return authors, author_detail

视图层

class AuthorsView(APIView):
    def post(self, request):
        author = AuthorSerializer(data=request.data)
        if author.is_valid():
            authors, authors_detail = author.save()
            return Response({"code": 100, "msg": {"username": authors.username, "age": authors_detail.age,
                                                  "gender": authors_detail.gender,
                                                  "addr": authors_detail.addr
                                                  }})
        else:
            return Response({"code": 101, "msg": author.errors})

路由层

urlpatterns = [
    path('authors/', AuthorsView.as_view()),
]