• Django REST framework序列化


    1、关于序列化与反序列化

    web有两种应用模式,一种是前后端不分离,一种是前后端分离,当前后端分离的时候,后端只需要向前端传输数据即可,不需要进行其他的操作;
    
    现阶段主流的数据格式为json格式,所以在restframework在前后端传输数据时,也主要是json数据,过程中就要需要把其他数据转换成json数据,
    比如数据库查询所有数据时,是queryset对象,那就要把这对象处理成json数据返回前端。


    序列化与反序列化

    增:效验请求数据 > 执行反序列化过程 > 保存数据库 > 将保存的对象序列化并返回
    
    删:判断要删除的数据是否存在 > 执行数据库删除
    
    改:判断要修改的数据是否存在 > 效验请求的参数 > 执行反序列化过程 > 保存数据库 > 将保存的对象序列化并返回
    
    查:查询数据库 > 将数据序列化并返回
    
    
    rest-framework的序列化组件:
          提供了定义序列化器Serializer的方法,可以快速根据Django ORM 或者其他库自动序列化/反序列化;


    2、Serializers序列化与反序列化

    序列化


    -使用drf的序列化组件
        -1 新建一个序列化类继承Serializer
        -2 在序列化类中写要序列化的字段
        
    -在视图中使用序列化的类
        -1 实例化序列化的类产生对象,在产生对象的时候,传入需要序列化的对象(queryset)
        -2 对象.data
        -3 return Response(对象.data)
    -高级用法:
        -source:可以指定字段(name   publish.name),可以指定方法,
        -SerializerMethodField搭配方法使用(get_字段名字)
            publish_detail=serializers.SerializerMethodField(read_only=True)
            def get_publish_detail(self,obj):
                return {'name':obj.publish.name,'city':obj.publish.city}
        -read_only:反序列化时,不传
        -write_only:序列化时,不显示


    案例:
    settings.py

    INSTALLED_APPS = [
        ...
        'rest_framework',
    ]


    models.py中建表

    from django.db import models
    
    # Create your models here.
    class Book(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        price = models.DecimalField(max_digits=5, decimal_places=2)
        publish_date = models.DateField()
        publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE)
        authors=models.ManyToManyField(to='Author')
        def __str__(self):
            return self.name
    
    
    class Author(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        age = models.IntegerField()
    
    
    class Publish(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        city = models.CharField(max_length=32)
        email = models.EmailField()
    
        def __str__(self):
            return self.name

    执行数据库迁移命令;


    在app下新建一个序列化类并继承Serializer :

    app01serializer.py

    from rest_framework import serializers
    
    # 序列化Author的类
    class AuthorSerializer(serializers.Serializer):
        name = serializers.CharField()
        age = serializers.CharField()
    
    
    # 序列化Book的类
    class BookSerializer(serializers.Serializer):
        # 指定source='name',表示序列化模型表中的name字段,重名命为name5,可以避免直接暴露数据库字段
        # 模型表中的字段和source指定的字段不能重名
        # name = serializers.CharField()
        name5 = serializers.CharField(source='name')
        # write_only 序列化的时候,该字段不显示
        # read_only 反序列化的时候,该字段不传
        # price = serializers.CharField()
        price = serializers.CharField(write_only=True)
    
        # 如果要取出版社的city--> source='publish.city'
        publish = serializers.CharField(source='publish.city')
    
        # source不仅可以指定一个字段,还可以指定一个方法
        # 在modles.py的Book表中写了一个test方法,并返回xxx
        xxx = serializers.CharField(source='test')
    
        # 比如要序列化出版社的详情; SerializerMethodField对应着一个方法,方法返回什么内容,publish_detail就是什么内容
        publish_detail = serializers.SerializerMethodField()
        # SerializerMethodField对应的方法,固定写法:get_字段名
        # 因为这个类是序列化Book的,参数obj就是Book对象,然后用Book对象去拿出版社的详情
        def get_publish_detail(self, obj):
            print(type(obj))
            return {'name':obj.publish.name, 'city':obj.publish.city}
    
        # 比如要返回所有的作者信息
        authors = serializers.SerializerMethodField()
        def get_authors(self, obj):
            # return [{'name': author.name, 'age': author.age} for author in obj.authors.all()]
            # 上面这种return的方式是用的列表推导式,当有变化时就要不断修改这个推导式,
            # 我们也可以再添加一个序列化的类,当有变化时修改类就行了
            # 此时在上面添加了一个序列化Author的类,在这里使用它
            authorser = AuthorSerializer(obj.authors.all(), many=True)
            return authorser.data


    在视图中使用序列化的类 :

    views.py

    from app01 import models
    from rest_framework.views import APIView
    from rest_framework.serializers import Serializer
    # Response本质也会是继承了Httpresponse,但是功能更强大了
    from rest_framework.response import Response
    # 导入新建的序列化类
    from app01.app01serializer import BookSerializer
    
    
    # Create your views here.
    class Books(APIView):
        def get(self, request):
            response = {"code":100, "msg":"查询成功"}
            books = models.Book.objects.all()
            # 如果序列化多条,要写many=True(序列化多条时,其实是序列化的queryset对象 )
            # 如果序列化一条,many=True可以不写(序列化一条时,就不是queryset了)
            bookser = BookSerializer(books, many=True)
            response['data'] = bookser.data
            print(type(bookser.data))
            return Response(response)


    urls.py

    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^books/', views.Books.as_view()),
    ]


    反序列化

    -使用继承了Serializers序列化类的对象,来进行反序列化
        -在自己写的序列化类中重写create方法
        -重写create方法,实现序列化
            -在序列化类中:
                def create(self, validated_data):
                    ret=models.Book.objects.create(**validated_data)
                    return ret
            -在视图中:
                def post(self,request):
                    bookser=BookSerializer(data=request.data)
                    if bookser.is_valid():
                        ret=bookser.create(bookser.validated_data)
                    return Response()


    在app01serializer.py的序列化Book的类中,重写create方法:

    # 序列化Book的类
    class BookSerializer(serializers.Serializer):
             ……
             ……
        # 重写create方法
        def create(self, validated_data):
            ret = models.Book.objects.create(**validated_data)
            return ret


    views.py

    from app01 import models
    from rest_framework.views import APIView
    from rest_framework.serializers import Serializer
    from rest_framework.response import Response
    # 导入新建的序列化类
    from app01.app01serializer import BookSerializer
    
    
    # Create your views here.
    class Books(APIView):
        def get(self, request):
            response = {"code":100, "msg":"查询成功"}
            books = models.Book.objects.all()
            # 如果序列化多条,要写many=True(序列化多条时,其实是序列化的queryset对象 )
            # 如果序列化一条,many=True可以不写(序列化一条时,就不是queryset了)
            bookser = BookSerializer(books, many=True)
            response['data'] = bookser.data
            print(type(bookser.data))
            return Response(response)
    
        def post(self, request):
            # 实例化产生一个序列化类的对象,data是要反序列化的字典
            bookser = BookSerializer(data=request.data)
            if bookser.is_valid():
                ret = bookser.create(bookser.validated_data)
            return Response()


    3、ModelSerializers序列化与反序列化

    序列化

    app01serializer.py

    from app01 import models
    class BookSerializer(serializers.ModelSerializer):
        class Meta:
            # 指定表模型
            model = models.Book
            # fields表示要序列化哪几个字段
            # fields=('nid','name')
    
            # exclude表示不序列化哪些字段,不能跟fields同时使用
            # exclude=['name',]
    
            # __all__表示序列化所有字段
            fields = ('__all__')
    
            # 深度是1,表示可以跨的表数量,官方建议不要超过10,个人建议不要超过3
            # 会拿到与此表深度关系为1的表中的所有数据,且不能定制化,与下面的方式各有不同的使用场景
            depth=1
    
        # 比如要序列化所有作者的详情信息(和Serializer中相同),这种方法可以定制化(代码在Meta类外面)
        # authors = serializers.SerializerMethodField()
        # def get_authors(self,obj):
        #     ret = AuthorSerializer(instance=obj.authors.all(), many=True)
        #     return ret.data


    反序列化

    #使用继承了ModelSerializers序列化类的对象,反序列化
        #在视图中:
            def post(self,request):
                bookser=BookSerializer(data=request.data)
                if bookser.is_valid():
                    ret=bookser.save()
                return Response()


    4、反序列化的校验

    app01serializer.py

    # 局部校验
    def validate_name(self,value):
        # value就是传过来的值,如:name:wei 这里的wei就是value
        print(value)
        raise exceptions.ValidationError('不能以sb开头')
        # if value.startswith('sb'):
        #     raise ValidationError('不能以sb开头')
        # return value
    
    #全局校验
    # 如果用了fields=('__all__')的方式,这里的attrs可能会找不到具体的字段
    def validate(self,attrs):
        # attrs是校验通过的数据,是一个字典
        print(attrs)
        # if attrs.get('price')!=attrs.get('xx'):
        #     raise exceptions.ValidationError('name和price相等,不正常')
        return attrs


    views.py

    class Books(APIView):
        def get(self,request):
         ...
    
        def post(self,request):
            #实例化产生一个序列化类的对象,data是要反序列化的字典
            bookser=BookSerializer(data=request.data)
            # bookser.data
            # raise_exception=True把校验的错误数据抛到前端,前后端分离项目用不到
            if bookser.is_valid(raise_exception=True):
                #清洗通过的数据
                bookser.save()
            else:
                # 抛出校验错误的信息
                print(bookser.errors['name'][0])
            return Response()
  • 相关阅读:
    nginx配置vue项目
    TexturePacker工具对素材打包
    java使用动态链接库
    java.lang.UnsatisfiedLinkError: no A in java.library.path
    pi4j与Spring Boot
    迪文屏串口修改数据
    迪文屏常用串口指令
    postcss-px-to-viewport移动端布局
    vue-lazyload延迟加载
    fastclick延迟300ms
  • 原文地址:https://www.cnblogs.com/weiyiming007/p/12511715.html
Copyright © 2020-2023  润新知