zoukankan      html  css  js  c++  java
  • drf之序列化组件(一):Serializer

    序列化组件:SerializerModelSerializerListModelSerializer

    Serializer  偏底层  ModelSerializer       重点  ListModelSerializer     辅助群改

    1.Serializer组件

     1)准备

    1models.py

    class User(models.Model):
        SEX_CHOICES =  [
    [0,”男”],    #前面是0还是”0”和IntergerField还是CharField有关
    [1,”女”]     #前面是填入的,后面是显示的
    ]
        name = models.CharField(max_length=64)
        pwd = models.CharField(max_length=32)
        phone = models.CharField(max_length=11, null=True, default=None)
        sex = models.IntegerField(choices=SEX_CHOICES, default=0)
        icon = models.ImageField(upload_to=”icon”, defult=’icon/defult.png’)   #需要在项目base目录下新建media文件夹,然后在media下建立icon文件夹
      (默认会找media下的icon文件夹)
    class Meta: db_table = ‘yq_user’ verbose_name = “用户表” verbose_name_plural = verbose_name def __str__(self): return “%s”%self.name

      2)在admin.py下注册User

    admin.site.register(models.User)

    3)在shell中迁移

    makemigrations、migrate

    get请求是要序列化,将后台数据返回给前台;post请求要反序列化,将前台数据给后台存入数据库中,同时也要序列化对象展示数据给前台。

     4)配置媒体资源

     1)在settings.py里配置media路径

    MEDIA_ROOT = os.path.join(BASE_DIR, ‘media’)

    2)在项目文件下的urls.py中     

    #media在根路由配置

    from django.views.static import serve
    from django.conf import setting
    
    urlpatterns = [
      ...
        url(r”^media/(?P<path>.*)”, serve, {‘document_root’: setting.MEDIA_ROOT})   #正则匹配时不要写$,可以一层层找
    ]

    3)数据库再迁移下

     用户对象(model对象或者query_set对象)、用户对象列表不能直接返回给前台,要序列化下对象。因此要用Serializer

    2)序列化

     1)配置路由

    urlpatterns = [
        url(r'^users/$', views.User.as_view()),
        url(r'^users/(?P<pk>.*)/$', views.User.as_view()),
    ]

    (2)自定义序列化类。在应用文件夹下新建serializers.py文件。

    序列化组件的工作方式与djangoforms组件相似

    from rest_framework import serializers
    
    class UserSerailizer(serializers.Serializer):
    
      #字段的类型和定义时一致,字段为想要返回给前台的内容(pwd不用返回就不写)
      name = serializers.CharField()    #序列化的括号里不需加条件
      phone = serlializers.CharField()
      #sex = serializers.IntegerField()
      #icon = serializers.ImageField()
    
       #由于sex默认返回的是0、1数字给前台,icon返回的不是全链接,因此要自定义序列化属性:定制返回的内容
    
      gender = serializers.SerializerMethodField()  #可以叫gender,也可以叫sex,不一定与字段名保持一致
    
      def get_gender(self, obj):    #必须以get开头,后面也必须和上面的gender对应
      #self是serializer对象,obj是模型类对象
        return obj.get_sex_display()     #get_xxx_display() 表示取到选项值
    
      
      #在settings.py中配置下MEDIA_URL = /media/
      from untitled1 import settings
      img =  serializer.SerializerMethodField()
      def get_img(self, obj):
        return “%s%s%s”%(r”http://127.0.0.1:8000”, settings.MEDIA_URL, str(obj.icon))
      #obj.icon不能直接作为数据返回,类型是ImageFile类型,可以通过str转化为str类型。

    3)在views.py中返回对象序列化后的json数据

    from . import serializers
    from rest_framework.views import APIView
    from rest_framework.response import Response
    
    class User(APIView):
    
        def get(self, request, *args, **kwargs):
            pk = kwargs.get('pk')   #通过有名分组匹配到的路径参数
            if pk:  #单查
                try:
                    user_obj = models.User.objects.get(pk=pk) #取到model对象
                    #将对象序列化取得dict数据
                    user_ser_data = serializers.UserSerializer(user_obj).data 
                    return Response({
                        "status": 0,
                        "msg": "ok",
                        "results": user_ser_data
                    })
                except:
                    return Response({
                        "status": 2,
                        "msg": "no user",
                    })
            else:  #群查
                user_obj_list = models.User.objects.all()
           #将对象列表序列化
                user_ser_data = serializers.UserSerializer(
                                    user_obj_list,many=True).data
                return Response({
                    "status": 0,
                    "msg": "ok",
                    "results":user_ser_data
                })

    总结:

    序列化ser:

    1)序列化给前台的字段个数可以由后台自己决定,但是提供的序列化字段的一定要和数据库的字段的类型和名字一致。

    2)自定义属性名:为了返回自定义的字段的值。属性名随意,值由固定的命名规范方法提供:get_属性名(self, obj)obj为参与序列化的model或者query_set对象。返回值就是自定义序列化属性的值。

    view

    1)从数据库中将要序列化给前台的model对象,或是多个model对象查询出来

    user_obj = models.User.objects.get(pk=pk)或者

    user_objs_list = models.User.objects.all()

    2)将对象交给序列化处理,产生序列化对象,如果序列化的是多个数据,要设置many=True

    user_ser = serializers.UserSerializer(user_obj)或者

    user_ser_list = serializers.UserSerializer(user_objs_list, many=True)

    3)序列化对象.data就是可以返回给前台的序列化数据,然后return Response返回

    3)反序列化

    反序列化考虑的问题:

    1)哪些字段必须反序列化

    2)字段都有哪些安全校验

    3)哪些字段需要提供额外的安全校验

    4)哪些字段间存在联合校验

    反序列化字段全都是用来入库的,不会出现自定义方法属性,但会出现设置校验规则(系统校验、局部钩子和全局钩子)的自定义属性(re_pwd)

    1)还是在刚才的serializers.py文件中

    class UserDeserializer(serializer.Serializer):
    
      name = serializers.CharField(
          required=True,
          max_length=64,     #自定义检验规则
          min_length=3,
          error_message = { #错误信息,不给是默认的
              ‘max_length’:’太长’,
                 ‘min_length’:’太短’,
    })
      pwd= serializers.CharField(required=True)  
      phone = serializers.CharField(required=False)
      sex = serializers.IntegerField(required=False)
    
      #自定义有校验规则的反序列化字段。不存入库,只是用来校验
      re_pwd = serializers.CharField(required=True)   #用来判断两次输入密码一样
    
    
      #局部钩子:validate_要校验的字段名(self, 当前要检验字段的值)
      #校验规则:校验成功返回原值,失败返回异常
      #局部钩子校验某个字段
      def validate_name(self, value):
        if ‘j’ in value.lower():  #名字中不能出现j
             #from rest_framework import exceptions
          raise exceptions.ValidationError(“名字非法”)
        return value    #必须返回,校验成功返回value,失败抛异常
     
       #全局钩子:固定写法validate(self, attrs)。attrs为系统与局部钩子校验通过的所有数据。(系统和全局之间还有个局部钩子)
      #校验时需要用到多个字段。比如两次密码输入一致
      #校验规则:校验成功返回原值,失败返回异常
      def validate(self, attrs):
        pwd = attrs.get(‘pwd’)    #只是取得
        re_pwd = attrs.pop(‘re_pwd’)    #取得并且删除(不需要入库)
        if  pwd != re_pwd:
          raise exceptions.ValidationError({“pwd“: “两次密码不一致”})
        return attrs   #必须返回,校验成功返回attrs,失败抛异常
    
      #要完成新增,需在serializers.py中的自定义反序列化类中重新create方法。
      def create(self, validated_data):    #在views.py中校验后,save方法调用时内部会调用create。
        #在所有校验规则完毕之后,数据(validated_data是已经校验好的数据)可以直接入库
        #from . import models
        return models.User.objects.create(**validated_data)

    2)在views.py下 的User类下写post方法(对post提交的数据反序列化)

    def post(self, request, *args, **kwargs):
      request_data = request.data   #字典
    #数据是否合法(增加对象必须是一个字典数据且有值)
      if not isinstance(request_data, dict) or not request_data:
        return Response({
          "status": 1,
                        "msg": "数据有误",
            })
     #数据类型合法,但数据内容不一定合法,需要校验数据,校验的(参与反序列化)数据需要赋值给data
      book_ser = serializers.UserDeserializer(data=request_data)  #必须关键字data赋值
      #序列化对象调用is_valid完成校验,校验失败信息存储在序列化对象.errors中
      if book_ser.is_valid():   
        book_obj = book_ser.save()  #校验通过,完成新增(save的返回值就是完成校验后create返回的对象)
        return Response({
          "status": 0,
                       "msg": "ok",
          "results":serializers.UserSerializer(book_obj).data
          #新增和修改,都要 将反序列化的对象 再序列化 返回给其前台
           })
      else:   #校验没通过(校验的错误信息存在book_ser的errors中)
        return Response({
          "status": 1,
              "msg": book_ser.errors,
    })

    反序列化总结:

    视图类中:

    1)把要校验的数据交给序列化类,由data接收;

    book_ser = serializers.UserDeserializer(data=request_data)

    2)走is_valid校验;

    if book_ser.is_valid():

    3)校验成功走save方法,校验失败返回errors

    book_obj = book_ser.save()

    序列化类中:

    1)设置必填与选填序列化字段,设置校验规则

    2)为需要额外校验的字段提供局部钩子函数,如果某些字段(如验证码)不入库且不参与全局钩子,可以将值取出pop校验(一般在全局钩子里)

    3)为有联合关系的字段们提供全局钩子。如果某些字段不入库,也取出pop校验(如二次输入的密码)

    4)重写create方法,完成校验通过的字段入库,得到新增的对象。

      

    ser = 自定义序列化类(instance=模型类对象, data=empty,  **kwargs)  #序列化时传入模型类对象(instance=可以不写,直接写对象),不需要写datadata是反序列化才有);**kwargs比如当对象是个列表时,可以加个many=True参数。

    ser = 自定义反序列化类(instance=None, data=数据)   #将要被反序列化的前端传来的数据传入data中。

  • 相关阅读:
    Python TIPS上一道关于人民币金额小写转大写的题
    C Primer Plus--C预处理器和C库(1)
    C Primer Plus--位操作
    C Primer Plus--结构和其他数据类型(2)
    计算机缓存方式对于程序运行的影响
    7. 整数反转
    服务器初始化安装docker、docker-compose
    nacos爬坑史-1
    Kafka 报错: Error Uncaught exception in scheduled task 'flush-log'
    CentOS中docker部署的项目CPU占用率持续100%以上
  • 原文地址:https://www.cnblogs.com/yq055783/p/13183131.html
Copyright © 2011-2022 走看看