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中。

 

posted @ 2020-06-23 17:12  yq055783  阅读(218)  评论(0编辑  收藏  举报