• ModelSerializer序列化器实战


    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

    优化操作#

    我们知道作者表和作者详情表的表关系是一对一的关系,那么新增数据的时候,就得先新增作者详情表,再增作者表的数据,但是在实际生活中,用户不知道表关系这码事,为了体验更好,可以重写create方法,同时存两个表的内容,给用户的感觉就是操作了一张表

    '''优化作者表的序列化器'''
    # 作者序列化器
    class AuthorSerializer(serializers.ModelSerializer):
        class Meta:
            # 指定和哪个表有关系
            model = models.Author
            # fields = '__all__'
            fields = ['id', 'name', 'age', 'telephone', 'addr','authordetail_info']
    
        # 重写字段telephone和addr
        telephone = serializers.CharField(write_only=True)
        addr = serializers.CharField(write_only=True,max_length=8,required=False)
    
    
        # 重写create,操作两个表
        def create(self, validated_data):
            # 先存作者详情
            authordetail = models.AuthorDetail.objects.create(telephone=validated_data.get('telephone'),addr=validated_data.get('addr'))
            # 存作者表
            author = models.Author.objects.create(author_detail=authordetail,name=validated_data.get('name'),age=validated_data.get('age'))
            # 这样只返回author对象就行,直接存了两个表,返回反序列化的对象
            return author
    

    image
    image

    Postman自行测试,我测了测都能用,有问题望指正~

    注意
    如果实际项目中不需要操作数据库可以使用APIView,如果操作数据库那么推荐使用GenericAPIView

  • 相关阅读:
    day057:Set集合、TreeSet集合、自然排序Comparable的使用
    python18 正则表达式
    关于JVM的一些问题
    nginx pod hook钩子优雅关闭示例详解
    人力资源管理软件让每位员工的记录触手可及
    2023年10月工作经验及问题整理总结
    基于图片相似度对视频进行抽帧
    在T3开发板上实现SylixOS最小系统(一)创建BSP工程
    CSDN每日一题学习训练——Python版(N皇后 II、买卖股票的最佳时机 II、编程通过键盘输入每一位运动员)
    mmdetection - 训练数据加载流程之pipeline
  • 原文地址:https://www.cnblogs.com/48xz/p/16084008.html