• DRF序列化和反序列化(一:Serializer)


    一:表关系如下

    from django.db import models
    
    # Create your models here.
    __all__=['Book','Publisher','Authon']
    
    class   Book(models.Model):
         title =models.CharField(max_length=32,verbose_name='图书名称')
         CHOICES=((1,'python'),(2,'go'),(3,'linux'))
         category=models.IntegerField(choices=CHOICES,verbose_name='图书类别')
         pub_time=models.DateTimeField(verbose_name='出版日期')
    
         authon=models.ManyToManyField('Authon')
         publisher=models.ForeignKey(to='Publisher',on_delete=None)
         def __str__(self):
              return self.title
    class Authon(models.Model):
         name= models.CharField(max_length=32, verbose_name='作者姓名')
         def __str__(self):
              return self.name
    class  Publisher(models.Model):
         title = models.CharField(max_length=32, verbose_name='出版社名称')
    
         def __str__(self):
              return self.title  

    二:使用django编写接口

      1:使用jsonResponse模块进行数据序列化。

    from django.http import JsonResponse
    class Bookview(View):
        #使用jsonResponse 当存在外键时,需要自己手动对数据进行处理。
        def get(self,request):
            book_list=models.Book.objects.values('id','title','pub_time','publisher',"category")
            book_list=list(book_list)
    
            for  book  in  book_list:
                print(book)
                publisher_id  = book['publisher']
                publisher_obj=models.Publisher.objects.filter(id=publisher_id).first()
                book['pulisher']={
                    'id':publisher_id,
                    'title':publisher_obj.title
                }
    
            return   JsonResponse(book_list,safe=False,json_dumps_params={'ensure_ascii':False})
    

     2:使用serialize模块进行数据序列化。

        def get(self,request):
            book_list=models.Book.objects.all()
            book_list=serializers.serialize('json',book_list,ensure_ascii=False )
    
            return   HttpResponse(book_list)
    

     3:使用serialize和JsonResponse不方便处

          a:遇到外键关系,需要非常繁琐的处理。

    三:使用rest_framework 中 serializers进行序列化和反序列化

          1:基本准备

             a:下载 rest-framewoke模块,pip install rest-framework

             b:首先要明白后端展示给前端页面的数据,可能是经过跨表查询的具体值。而前端传送给后端,并不需要传送具体的值,也就是说前端和后端对同一个资源传递的数据类型可能不一样。比如性别,前端展示的是,男,女。但是后端在数据库存储的时候,往往是0,1

            c:新建文件serializers.py(用于编写序列化规则)

            d:settings中注册app

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'SerDemo',
        'rest_framework'    #app注册
    ]
    

      2:serializers序列化

             a:设定路由

                --注意需要调用as_view方法

    from django.urls import path,include
    from SerDemo import views
    urlpatterns = [
        path('list/', views.BookApiView.as_view()),
    
    ]

          b:在serializes.py编写序列化规则

             --注意序列化规则内每一个字段都和models字段相对应。重点, 

             --外键关系一对多和多对多需要注意

             --read_only=True(只进行序列化),同理write_only=True(该字段只进行反序列化)

    from rest_framework import serializers
    from  SerDemo.models import Book
    #一对多外键关系序列化处理
    class  PublisherSerializers(serializers.Serializer):
         id = serializers.IntegerField()
         title=serializers.CharField(max_length=32)
    
    #多对多外键关系序列化处理
    class  AuthonSerializers(serializers.Serializer):
         id = serializers.IntegerField()
         name=serializers.CharField(max_length=32)
    
    class  BookSerializers(serializers.Serializer):
        #不需要校验
        id = serializers.IntegerField(required=False,)
        title = serializers.CharField(max_length=32)
        CHOICES = ((1, 'python'), (2, 'go'), (3, 'linux'))
        category = serializers.ChoiceField(choices=CHOICES, source="get_category_display",read_only=True)
        pub_time = serializers.DateTimeField()
        #处理一对多
        publisher=PublisherSerializers(read_only=True)
        #处理多对多外键关系  many=True
        authon=AuthonSerializers(many=True,read_only=True)
        
    

      c:视图函数的编写

             --导包 (APIView,Response)

             --视图函数继承APIView  

             --many默认参数不写默认序列化一个对象,many=True 表示序列化多个对象

             --get请求会对应get方法

    from  SerDemo import models
    from  rest_framework.views import APIView     #视图函数继承APIView  不是View
    from rest_framework.response import Response  #用于返回值
    #BookSerializers  自己定义的序列化规则
    from SerDemo.serializers import *
    
    class BookApiView(APIView):
        def  get(self,request):
            book_obj = models.Book.objects.all()
            #序列化多组数据 和一个对象,需要many=TRUE  默认一个
           ret  =BookSerializers(book_obj,many=True)
            #序列化的数据在data属性中
            return  Response(ret.data)
    

      3:serializers反序列化

        a:在serializes.py编写反序列化规则   

           --首先序列化,我们常常需要把外键对象的值获取给前端,而反序列化,后端仅仅需要数据库一个id就能进行数据库值的插入。

           --write_only表示该字段只是反序列化使用,前端发送时key也应该和该值对应

           --注意一对多,多对多关系,choices的字段

    class  BookSerializers(serializers.Serializer):
        #不需要校验
        id = serializers.IntegerField(required=False,)
        title = serializers.CharField(max_length=32,validators=[my_validata])
        CHOICES = ((1, 'python'), (2, 'go'), (3, 'linux'))
        category = serializers.ChoiceField(choices=CHOICES, source="get_category_display",read_only=True)
        w_category=serializers.ChoiceField(choices=CHOICES,write_only=True)
        pub_time = serializers.DateTimeField()
    
        #处理一对多
        publisher=PublisherSerializers(read_only=True)
        publisher_id=serializers.IntegerField(write_only=True)
    
        #处理多对多外键关系  many=True
        authon=AuthonSerializers(many=True,read_only=True)
        authon_id =serializers.ListField(write_only=True)
    

        b:views文件中编写post的请求,对数据进行添加。

           --添加数据需要在BookSerializers重新编写create方法

           --注意返回值

           --所有的数据都在request.data方法中,(与View方法存在request.get,request.post中不同,该方法对这些方法进行封装)  

     def post(self,request):
            # print(request.data)
            data = BookSerializers(data=request.data)
            #进行数据验证,并且在BookSerializers中重写create方法
            if  data.is_valid():
                data.save()
                return Response(data.data)
            else:
                return Response(data.errors)
    

      c:编写create方法

    class  BookSerializers(serializers.Serializer):
        #不需要校验
        id = serializers.IntegerField(required=False,)
        title = serializers.CharField(max_length=32,validators=[my_validata])
        CHOICES = ((1, 'python'), (2, 'go'), (3, 'linux'))
        category = serializers.ChoiceField(choices=CHOICES, source="get_category_display",read_only=True)
        w_category=serializers.ChoiceField(choices=CHOICES,write_only=True)
        pub_time = serializers.DateTimeField()
    
        #处理一对多
        publisher=PublisherSerializers(read_only=True)
        publisher_id=serializers.IntegerField(write_only=True)
    
        #处理多对多外键关系  many=True
        authon=AuthonSerializers(many=True,read_only=True)
        authon_id =serializers.ListField(write_only=True)
    
        #向服务器添加数据,需要实现该方法
        def  create(self, validated_data):
           book =Book.objects.create(title=validated_data['title'],category=validated_data['w_category'],
                                     pub_time=validated_data['pub_time'],
                                     publisher_id=validated_data['publisher_id']
                                     )
    
           #添加多对多关系
           book.authon.add(*validated_data['authon_id'])
    
           return book
    

      d:put实现更新

            --路由分发   path('retrieve/<int:id>',views.BookEditView.as_view())

            --代码编写

                --partial参数

        def put(self,request,id):
            print(request.data)
            book_obj = Book.objects.filter(id=id).first()
            # partial   True 表示可以进行部分字段跟新,Flase 表示全部跟新,默认False
            book_serializers = BookSerializers(book_obj,data=request.data,partial=True)
    
            #需要重写 update
            if book_serializers.is_valid():
                book_serializers.save()
                return Response(book_serializers.validated_data)
            else:
                return Response(book_serializers.errors)
    

              --重写update方法

    #数据跟新
        def  update(self, instance, validated_data):
             print(validated_data.get('authon'))
             instance.title =validated_data.get('title',instance.title)
             instance.category=validated_data.get('category',instance.category)
             instance.pub_time =validated_data.get('pub_time',instance.pub_time)
             instance.publisher_id =validated_data.get('publisher_id',instance.publisher_id)
    
             if  validated_data.get('authon_id'):
                 instance.authon.set(validated_data.get('authon_id'))
             instance.save()
             return instance
    

      e:实现delete方法

        def  delete(self,request,id):
            book_obj = Book.objects.filter(id=id).first()
            book_obj.delete()
            return  Response("")
    

       4:serializers字段校验扩展

        a:局部钩子校验

             --校验字段方法,固定格式validate_字段名

             -- 参数value,就是该字段的值

             -- 返回值 

    #单个字段进行校验
        def   validate_title(self, value):
            if  'python' not in value.lower:
                return  serializers.ValidationError('标题必须含有python')
            return value
    

     b:全局钩子多个字段联合校验

        --方法 validate为固定方法

        --attrs保存联合字段的字段值

        --注意返回值

        #全局钩子对字段进行联合校验
        def  validate(self, attrs):
            if  attrs['category'] =='linux' and  attrs['publisher_id']==3:
                return attrs
            else:
                return serializers.ValidationError('类型或出版社错误')
    

      c:自定义钩子验证 

    #自定义校验
    #在需要进行验证的字段引用  title = serializers.CharField(max_length=32,validators=[my_validata])
    #优先级大于 validata_title 局部钩子
    def  my_validata(value):
        if value in '敏感信息':
            raise serializers.ValidationError('不能含有敏感信息')
        return value
    

      

      

      

  • 相关阅读:
    [转载]支付宝钱包手势密码破解实战(root过的手机可直接绕过手势密码)
    记大神的一次反汇编/更新
    关于获取某月某日最后一天时Calendar的cal.getActualMaximum(Calendar.DAY_OF_MONTH)的吐槽
    第一章:shiro简介
    [转] JAVA分为三个体系,JavaSE,JavaEE,JavaME(J2ME)的区别以及各个版
    JVM中GC浅解:垃圾回收的了解
    nginx redirect ignore port 两层nginx跳转忽略了端口
    [复习]java中hashCode的作用
    【转载】java工程师学习之路---给自己的目标
    java中的内部类
  • 原文地址:https://www.cnblogs.com/yingjp/p/10603465.html
Copyright © 2020-2023  润新知