drf03 序列化器

一、序列化器-Serializer

作用:

1. 序列化,序列化器会把模型对象转换成字典,经过response以后变成json字符串
2. 反序列化,把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型
3. 反序列化,完成数据校验功能

1. 定义序列化器

1.1 创建项目

python manage.py startapp app02_serializer

1.2 构建模型

from django.db import models
# Create your models here.
class BookAPIView(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    author = models.CharField(max_length=32)
    publish = models.CharField(max_length=32)

1.3 根据模型定义一个序列化器

from rest_framework import serializers
# 声明序列化器,所有的序列化器都要直接或者间接继承于 Serializer
# 其中,ModelSerializer是Serializer的子类,ModelSerializer在Serializer的基础上进行了代码简化
class BookSerializer(serializers.Serializer):
    # 1. 需要进行数据转换的字段
    id = serializers.IntegerField(read_only=True, write_only=False)
    name = serializers.CharField(max_length=32) 
    price = serializers.DecimalField(max_digits=5, decimal_places=2)
    author = serializers.CharField(max_length=32)
    publish = serializers.CharField(max_length=32)
    # 2. 如果序列化器集成的是ModelSerializer,则需要声明调用的模型信息

    # 3. 验证代码

    # 4. 编写添加和更新模型的代码

注意:serializer不是只能为数据库模型类定义,也可以为非数据库模型类的数据定义。serializer是独立于数据库之外的存在。

1.4 总结 - 参数


    定义字段类型可以都用CharField,后续根据字段类型再去处理
    常用参数
      many   				  # 默认为False 多条数据要设置为 many=True
      max_length、min_length
      read_only、write_only、  # 这两个默认为False ,针对特定字段赋予权限
      required、               # 表示在反序列化时,需要输入数据
      validators、             # 该字段使用的验证器
      label                    # 取别名 和model类似
      source 对象的字段、跨表字段 、[函数内存地址] # 高级用法

(1) 常用字段类型

字段 字段构造方式
BooleanField BooleanField()
NullBooleanField NullBooleanField()
CharField CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
EmailField EmailField(max_length=None, min_length=None, allow_blank=False)
RegexField RegexField(regex, max_length=None, min_length=None, allow_blank=False)
SlugField SlugField(maxlength=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+
URLField URLField(max_length=200, min_length=None, allow_blank=False)
UUIDField UUIDField(format='hex_verbose') format: 1) 'hex_verbose'"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex'"5ce0e9a55ffa654bcee01238041fb31a" 3)'int' - 如: "123456789012312313134124512351145145114" 4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a"
IPAddressField IPAddressField(protocol='both', unpack_ipv4=False, **options)
IntegerField IntegerField(max_value=None, min_value=None)
FloatField FloatField(max_value=None, min_value=None)
DecimalField DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置
DateTimeField DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)
DateField DateField(format=api_settings.DATE_FORMAT, input_formats=None)
TimeField TimeField(format=api_settings.TIME_FORMAT, input_formats=None)
DurationField DurationField()
ChoiceField ChoiceField(choices) choices与Django的用法相同
MultipleChoiceField MultipleChoiceField(choices)
FileField FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
ImageField ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
ListField ListField(child=, min_length=None, max_length=None)
DictField DictField(child=)

(2) 选项参数:

参数名称 作用
max_length 最大长度
min_length 最小长度
allow_blank 是否允许为空
trim_whitespace 是否截断空白字符
max_value 最大值
min_value 最小值

(3) 通用参数:

参数名称 说明
read_only 表明该字段仅用于序列化输出,默认False
write_only 表明该字段仅用于反序列化输入,默认False
required 表明该字段在反序列化时必须输入,默认True
default 反序列化时使用的默认值
allow_null 表明该字段是否允许传入None,默认False
validators 该字段使用的验证器
error_messages 包含错误编号与错误信息的字典
label 用于HTML展示API页面时,显示的字段名称
help_text 用于HTML展示API页面时,显示的字段帮助提示信息

2. 创建序列化对象

定义好Serializer类后,就可以创建Serializer对象了。

Serializer的构造方法为:

BookSerializer(instance=None, data=empty, **kwarg)

说明:

1)用于序列化时,将模型类对象传入instance参数

2)用于反序列化时,将要被反序列化的数据传入data参数

3)除了instance和data参数外,在构造Serializer对象时,还可通过context参数额外添加数据,如

book_ser = BookSerializer(account, context={'request': request})

通过context参数附加的数据,可以通过Serializer对象的context属性获取。

  1. 使用序列化器的时候一定要注意,序列化器声明了以后,不会自动执行,需要我们在视图中进行调用才可以。
  2. 序列化器无法直接接收数据,需要我们在视图中创建序列化器对象时把使用的数据传递过来。
  3. 序列化器的字段声明类似于我们前面使用过的表单系统。
  4. 开发restful api时,序列化器会帮我们把模型数据转换成字典.
  5. drf提供的视图会帮我们把字典转换成json,或者把客户端发送过来的数据转换字典.

3. 序列化器的使用

序列化器的使用分两个阶段:

  1. 在客户端请求时,使用序列化器可以完成对数据的反序列化。
  2. 在服务器响应时,使用序列化器可以完成对数据的序列化。

3.1序列化

使用序列化器进行序列化的时候,只需要传入instance-对象即可,并且只需要调用data 方法就能获取序列化以后的结果

book_queryset = models.BookAPIView.objects.all()
book_ser = BookModelSerializer(instance=book_queryset, many=True)
book_ser.data

3.2 反序列化

3.2.1 数据验证
(1) is_valid 验证是否成功
  1. 使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象。

  2. 在获取反序列化的数据前,必须调用is_valid()方法进行验证,验证成功返回True,否则返回False。

  3. 验证成功,需要调用序列化对象的save()保存数据,不调用这个方法不能真正的保存,当然保存可能牵涉到create、update方法的重写,可以参考modelserializer,然后通过序列化器对象的validated_data属性获取数据

  4. 验证失败,可以通过序列化器对象的errors属性获取错误信息,返回字典,包含了字段和字段的错误。如果是非字段错误,可以通过修改REST framework配置中的NON_FIELD_ERRORS_KEY来控制错误字典中的键名。

  book_obj = models.BookAPIView.objects.filter(pk=pk)
  book_ser = BookSerializer(instance=book_obj, data=request.data)
         if book_ser.is_valid():
            book_ser.save() 
            book_ser.data
         else:
            book_ser.errors
(2) validators 在字段中自己定义
from rest_framework import serializers
from app02_serializer import models
from rest_framework.exceptions import ValidationError

    
    
    # 可用于局部过滤
def clean_name(data):
    if len(data) > 3:
        raise ValidationError('名字太长了')
    else:
        return data

class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True, write_only=False)
    name = serializers.CharField(max_length=32,validators=[clean_name]) # validators=[] 列表中写函数内存地址
    price = serializers.DecimalField(max_digits=5, decimal_places=2)
    author = serializers.CharField(max_length=32)
    publish = serializers.CharField(max_length=32)

(3) validate 钩子函数
from rest_framework import serializers
from app02_serializer import models
from rest_framework.exceptions import ValidationError
# 局部钩子 - validate_字段名  data 是 price字段
def validate_price(self, data):
    if data > 10:
        pass
    else:
        raise ValidationError('价格太低了')
    return data

# 全局钩子 - validate    data 是所有数据
def validate(self, data):
    name = data.get('name')
    author = data.get('author')
    if name == author:
        pass
    else:
        raise ValidationError('作者和书名不一致')
    return data
3.2.2 数据保存

前面的验证数据成功后,我们可以使用序列化器来完成数据反序列化的过程.这个过程可以把数据转成模型类对象

自己定义了一个响应类,用来储存信息

响应消息类
class MyResponse(object):
    def __int__(self):
        # 定制化响应内容
        self.status = 200
        self.msg = "请求成功"
        self.data = ""

    @property
    def get_dict(self):
        if self.__dict__:
            return self.__dict__

if __name__ == '__main__':
    a = MyResponse()
    a.status = 202
    # a.msg = '请求成功'
    # a.data = '数据'
    print(a.get_dict)


配置路由
# 为以下方法配置路由 - get-all post
path('books/', views.BooksView.as_view()),
# 为以下方法配置路由 - get/put/delete - pk
re_path(r'^books/(?P<pk>\d+)/', views.BookView.as_view()),
(1)get方法 - pk
from rest_framework.views import APIView
from app02_serializer import models
from app02_serializer.myserializer.ser01 import BookSerializer
from rest_framework.response import Response
from app02_serializer.utils.reponseUtil import MyResponse
class BookView(APIView):
    # get 方法获取单条或多条数据
    def get(self, request, pk):
        print('get-pk方法')
        response_msg = MyResponse()
        # 根据pk获取
        # 用一个类,毫无疑问,一定要实例化
        # 要序列化谁,就把谁传过来
        book_obj = models.BookAPIView.objects.filter(id=pk).first()  # # 调用类的__init__
        # book_ser.data   序列化对象.data就是序列化后的字典
        book_ser = BookSerializer(instance=book_obj)  # 如果不加 many = True 则只能返回一个对象

        response_msg.status = 200
        response_msg.msg = '请求成功'
        response_msg.data = book_ser.data
        return Response(response_msg.get_dict)
(2) get方法 - all
from rest_framework.views import APIView
from app02_serializer import models
from app02_serializer.myserializer.ser01 import BookSerializer
from rest_framework.response import Response
from app02_serializer.utils.reponseUtil import MyResponse

class BooksView(APIView):
    # get 方法获取单条或多条数据
    def get(self, request):
        print('get-all方法')
        response_msg = MyResponse()
        # 获取全部数据
        book_queryset = models.BookAPIView.objects.all()
        book_ser = BookSerializer(instance=book_queryset, many=True)  # 序列化多条,如果序列化一条,不需要写
        response_msg.status = 200
        response_msg.msg = '请求成功'
        response_msg.data = book_ser.data
        return Response(response_msg.get_dict)
(3) post方法 - 需重写create方法
from rest_framework.views import APIView
from app02_serializer import models
from app02_serializer.myserializer.ser01 import BookSerializer
from rest_framework.response import Response
from app02_serializer.utils.reponseUtil import MyResponse

class BooksView(APIView):
 # post 创建数据
    def post(self, request):
        print('post方法')
        response_msg = MyResponse()
        # 修改才有instance,新增没有instance,只有data
        book_ser = BookSerializer(data=request.data)
        if book_ser.is_valid():
            book_ser.save()
            response_msg.status = 200
            response_msg.msg = '创建成功'
            response_msg.data = book_ser.data
        else:
            response_msg.status = 201
            response_msg.msg = '创建失败'
            response_msg.data = book_ser.errors
        return Response(response_msg.get_dict)
(4) put方法 - 需重写update方法
from rest_framework.views import APIView
from app02_serializer import models
from app02_serializer.myserializer.ser01 import BookSerializer
from rest_framework.response import Response
from app02_serializer.utils.reponseUtil import MyResponse

class BookView(APIView):
  # put 方法更新数据,全局更新
    def put(self, request, pk):
        print('put方法')
        # 根据pk修改
        response_msg = MyResponse()
        # 找到这个对象
        book_obj = models.BookAPIView.objects.filter(pk=pk)
        # 得到一个序列化类的对象
        # boo_ser=BookSerializer(book,request.data)
        book_ser = BookSerializer(instance=book_obj, data=request.data)
        if book_ser.is_valid():
            book_ser.save()
            response_msg.status = 200
            response_msg.msg = '更新成功'
            response_msg.data = book_ser.data
        else:
            response_msg.status = 201
            response_msg.msg = '更新失败'
            response_msg.data = book_ser.errors
        return Response(response_msg.get_dict)
    
(5) delete方法
from rest_framework.views import APIView
from app02_serializer import models
from app02_serializer.myserializer.ser01 import BookSerializer
from rest_framework.response import Response
from app02_serializer.utils.reponseUtil import MyResponse

class BookView(APIView):
  def delete(self, request, pk):
        print('delete方法')
        response_msg = MyResponse()
        book_obj = models.BookAPIView.objects.filter(pk=pk).delete()
        book_res = BookSerializer(data=request.data)
        book_res.is_valid()
        if book_obj:
            response_msg.status = 200
            response_msg.msg = '删除成功'
            response_msg.data = book_res.data
        else:
            response_msg.status = 201
            response_msg.msg = '删除失败'
            response_msg.data = book_res.errors
        return Response(response_msg.get_dict)
3.2.3 附加说明
(1) create( )方法

当使用post方法保存数据的时候,需要在自定义的序列化器中重写create方法用来保存数据

from rest_framework import serializers
from app02_serializer import models
from rest_framework.exceptions import ValidationError

class BookSerializer(serializers.Serializer):
# post方法 要重写create 方法
    def create(self, validated_data):
        # 获取一个类 Book
        instance = models.BookAPIView.objects.create(**validated_data)
        return instance
(2) update() 方法
from rest_framework import serializers
from app02_serializer import models
from rest_framework.exceptions import ValidationError

class BookSerializer(serializers.Serializer):
    # put 方法 要重写update
    def update(self, instance, validated_data):
        instance = models.BookAPIView.objects.create(**validated_data)
        # instance = models.Book.objects.create(name=validated_data.get('name'))
        return instance

3.3 序列化器之高级用法-source方法

source方法主要用来指定字段 或者跨表字段 + SerializerMethodField + 自定义方法

3.3.1 models.py
from django.db import model

# 关系备注:book - publish 一对多
# 关系备注:book - author  多对多
class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.IntegerField()
    pub_date = models.DateField()
    publish = models.ForeignKey("Publish", on_delete=models.CASCADE, null=True)
    authors = models.ManyToManyField("Author")

    def __str__(self):
        return self.title

    def test(data):
        import datetime
        return '{}'.format(datetime.datetime.now())


class Publish(models.Model):
    name = models.CharField(max_length=32)
    email = models.EmailField()


class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()

    def __str__(self):
        return self.name
3.3.2 ser.py
  1. source 方法只能是models.py 中 且 是与 该表对象 是有关联的

  2. 用source 可以用来表示这个序列化对象的字段名 + 函数 + 跨表字段

from rest_framework import serializers

class BookManySerializer(serializers.Serializer):
    # book.publish
    # book.price
    # book.xxx--->book.title
    # book.authors.all

    xxx=serializers.CharField(source='title') # 字段名
    price=serializers.CharField()  
    pub_date=serializers.CharField(source='test') # 对应方法
    publish=serializers.CharField(source='publish.email') # 一对一关系
    authors=serializers.SerializerMethodField() # 多对多关系
    
    #它需要有个配套方法,方法名叫get_字段名,返回值就是要显示的东西 
    def get_authors(self,instance):
        # book对象
        authors=instance.authors.all()  # 取出所有作者
        ll=[]
        for author in authors:
            ll.append({'name':author.name,'age':author.age})
        return ll
3.3.3 urls.py
# manymodelserializer
re_path(r'^books_manymodel/(?P<pk>\d+)/', views.BookManyModelView.as_view()),

3.3.4 views.py

from rest_framework.views import APIView
from app02_serializer import models
from app02_serializer.myserializer.ser02 import BookManySerializer
from rest_framework.response import Response

class BookManyModelView(APIView):
    def get(self, request, pk):
        book_obj = models.Book.objects.filter(id=pk).first()
        book_ser = BookManySerializer(book_obj)
        return Response(book_ser.data)

4.模型序列化器

如果我们想要使用序列化器对应的是Django的模型类,DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个Serializer类。

ModelSerializer与常规的Serializer相同,但提供了:

  • 基于模型类自动生成一系列字段
  • 基于模型类自动为Serializer生成validators,比如unique_together
  • 包含默认的create()和update()的实现

4.1 定义

from rest_framework import serializers
from app02_serializer import models
from rest_framework.exceptions import ValidationError

class BookModelSerializer(serializers.ModelSerializer):
       # 如果模型类序列化器,必须声明本次调用是哪个模型,模型里面的哪些字段
    class Meta:
        model = models.BookAPIView
       
        # 全部字段
          fields = '__all__' # 所有字段
        
        # 选择字段
        # fields = ['name','price','author']
            
        # 排除字段
        # exclude = ['id']  # 去除id
        
        # 额外字段
        extra_kwargs = {
            'id': {'read_only': True}
        }
        
        # 注意:
        # fields 和 exclude 只能选择一个
        # 字段必须是该模型中的字段

4.2 指定字段

指定字段有两种方式 :

​ fields

​ exclude

# fields 
# 全部
fields = '__all__' # 所有字段
# 选择部分字段
fields = ['name','price','author']


# exclude
exclude = ['id']  # 去除id       

4.3 额外参数

我们可以使用extra_kwargs参数为ModelSerializer添加或修改原有的选项参数

# 这参数的话,其实是跟序列化器的用法是一样的但是写法不同而已

# 两者写法对比
# 序列化器
  id = serializers.IntegerField(read_only=True, write_only=False)

# 模型序列化器
 extra_kwargs = {
            'id': {'read_only': True,'write_only':False}
        }

4.4 使用

from rest_framework.views import APIView
from app02_serializer import models
from app02_serializer.myserializer.ser02 import BookManySerializer
from rest_framework.response import Response

class BookManyModelView(APIView):
    def get(self, request, pk):
        book_obj = models.Book.objects.filter(id=pk).first()
        book_ser = BookManySerializer(book_obj)
        return Response(book_ser.data)
posted @ 2023-05-25 11:16  派森的猫  阅读(25)  评论(0)    收藏  举报