4.序列化组件

序列化组件介绍

# 序列化和反序列化
序列化:将python当中的对象转换成json格式的字符串
反序列化:将json格式的字符串转化成python当中的对象

# 序列化组件
1、序列化:序列化器会把模型对象转换成字典,经过response返回后变成json字符串
2、反序列化:把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型对象(反序列化要完成数据校验功能)

DRF中最常用的序列化组件:Serializer、ModelSerializer、ListModelSerializer

序列化组件常用参数

  常用字段类型

下面的表格中我们列出了序列化器中常用的字段类型,对于DRF框架中序列化器所有的字段类型,我们可以到 rest_framework.fields 模块中进行查看。

字段字段构造方式
BooleanField BooleanField()
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)
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)
ChoiceField

ChoiceField(choices)

choices与Django的用法相同

ImageField ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)

  选项参数

 通用选项参数

参数名称 说明
read_only 默认False,若设置为True,表明对应字段只在序列化操作时起作用。为true时postman中可以看到该字段,修改时不需要传该字段
write_only 默认False,若设置为True,表明对应字段只在反序列化操作时起作用。为true时postman看不到该字段,修改时该字段需要传
required 默认True,表明对应字段在数据校验时必须传入
default 序列化和反序列化时使用的默认值
allow_null

表明该字段是否允许传入None,默认False

validators

该字段使用的验证器

error_messages

包含错误编号与错误信息的字典

label

用于HTML展示API页面时,显示的字段名称,理解为对字段的注释说明即可

 常用选项参数

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

参数说明:

·max_length和min_length是针对字符串类型的参数;

·max_value和min_value是针对数字类型的参数。

Serializer序列化器

  序列化(get请求获取数据)

1、在models.py中创建一张表

class Book(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=64)
models.py

2、写一个序列化的类,继承Serializer(在类中写要序列化的字段,想序列化哪个字段,就在类中写哪个字段)

from rest_framework import serializers

class BookSerializer(serializers.Serializer):
    id = serializers.CharField()
    name = serializers.CharField()
    price = serializers.CharField()
    author = serializers.CharField()
    publish = serializers.CharField()
ser.py

3、匹配好对应的路由

from django.contrib import admin
from django.urls import path,re_path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    re_path('books/(?P<pk>\d+)', views.BookView.as_view())
]
urls.py

4、在视图类中使用,导入对应的模块,实例化得到序列化类的对象,把要序列化的对象传入

from rest_framework.views import APIView
from app01.models import Book
from app01.ser import BookSerializer
from rest_framework.response import Response  # drf提供的响应对象
# from django.http import JsonResponse

class BookView(APIView):
    def get(self,request,pk):
        book = Book.objects.filter(id=pk).first()
        book_ser =  BookSerializer(book)  # 调用类的__init__方法
        print(book_ser.data)  # 序列化对象.data就是序列化后的字典
        # {'id': '1', 'name': 'python',...}
        # 把字典返回,如果不使用rest_framework提供的Response,就得使用JsonResponse
        return Response(book_ser.data)
        # return JsonResponse(book_ser.data)
views.py

  反序列化(put请求修改数据)

1、在models.py中创建一张表

class Book(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=64)
models.py

2、写一个序列化的类,继承Serializer(在类中写要序列化的字段,想序列化哪个字段,就在类中写哪个字段)

from rest_framework import serializers

class BookSerializer(serializers.Serializer):
    # id = serializers.CharField()
    name = serializers.CharField(max_length=16, min_length=6)
    price = serializers.CharField()
    author = serializers.CharField()
    publish = serializers.CharField()
ser.py

3、匹配好对应的路由

from django.contrib import admin
from django.urls import path,re_path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    re_path('books/(?P<pk>\d+)', views.BookView.as_view()),
]
urls.py

4、在视图类中使用,导入对应的模块,实例化得到序列化类的对象,把需要修改的对象传入,修改的数据传入,并进行数据的校验

两种传入方式:

boo_ser=BookSerializer(book,request.data)
boo_ser=BookSerializer(instance=book,data=request.data)
from rest_framework.views import APIView
from app01.models import Book
from app01.ser import BookSerializer
from rest_framework.response import Response  # drf提供的响应对象

class BookView(APIView):
    def put(self,request,pk):
        response_msg = {'status':100,'msg':'数据校验成功'}
        # 找到这个对象
        book = Book.objects.filter(id=pk).first()
        # 得到一个序列化类的对象
        book_ser = BookSerializer(book,request.data)
        # book_ser = BookSerializer(instance=book,data=request.data)

        # 需要校验数据(比较form表单数据的校验)
        if book_ser.is_valid():
            book_ser.save()  # 报错
            response_msg['data'] = book_ser.data
        else:
            response_msg['status'] = 101
            response_msg['msg'] = '数据校验错误'
            response_msg['data'] = book_ser.errors
        return Response(response_msg)
views.py

注:当直接使用sava保存会报NotImplementedError,需要重写update方法

def update(self, instance, validated_data):
    #instance是book这个对象
    #validated_data是校验后的数据
    instance.name=validated_data.get('name')
    instance.price=validated_data.get('price')
    instance.author=validated_data.get('author')
    instance.publish=validated_data.get('publish')
    instance.save()  #book.save()   django 的orm提供的
    return instance
ser.py

5、钩子函数(如果校验不够,需要用钩子函数)

# 局部钩子
from rest_framework.exceptions import ValidationError
def validate_price(self, data):  # validate_字段名,接收一个参数
    # 如果价格小于20,就校验不通过
    print(data, type(data))  # 139.99 <class 'str'>
    if float(data)>10:
        return data
    else:
    #校验失败,抛异常
        raise ValidationError('价格太低')
ser.py
# 全局钩子
from rest_framework.exceptions import ValidationError
def validate(self, validate_data):  # 全局钩子
    print(validate_data)
    author = validate_data.get('author')
    publish = validate_data.get('publish')
    if author == publish:
        raise ValidationError('作者名字跟出版社一样')
    else:
        return validate_data
ser.py

6、可以使用 author=serializers.CharField(validators=[check_author]) # validators=[] 列表中写函数内存地址

# 该函数写在ser.py文件里面,但是不写入序列化类里面
def check_author(data):
    if data.startswith('jiang'):
        raise ValidationError('作者名字不能以jiang开头')
    else:
        return data

# 然后再序列化类的字段中田间validators=[函数名]属性
View Code

  查询所有(many)

在视图里面新建一个类

path('books/', views.BooksView.as_view()),
from rest_framework.views import APIView
from app01.models import Book
from app01.ser import BookSerializer
from rest_framework.response import Response  # drf提供的响应对象

class BooksView(APIView):
    def get(self,request):
        response_msg = {'status':100,'msg':'数据校验成功'}
        books = Book.objects.all()
        book_ser = BookSerializer(books,many=True)  # 序列化多条,如果序列化一条不需要写many
        response_msg['data']=book_ser.data
        return Response(response_msg)
views.py

  新增数据

在视图里面新建一个类

path('books/', views.BooksView.as_view()),
from rest_framework.views import APIView
from app01.models import Book
from app01.ser import BookSerializer
from rest_framework.response import Response  # drf提供的响应对象

def post(self,request):
    response_msg = {'status': 100, 'msg': '成功'}
    #修改才有instance,新增没有instance,只有data
    book_ser = BookSerializer(data=request.data)
    # book_ser = BookSerializer(request.data)  # 这个按位置传request.data会给instance,就报错了
    # 校验字段
    if book_ser.is_valid():
        book_ser.save()
        response_msg['data']=book_ser.data
    else:
        response_msg['status']=102
        response_msg['msg']='数据校验失败'
        response_msg['data']=book_ser.errors
    return Response(response_msg)
views.py

注:当直接使用sava保存会报NotImplementedError,需要重写create方法

from rest_framework import serializers
from app01.models import Book
class BookSerializer(serializers.Serializer):
    def create(self, validated_data):
        # Book.objects.create(name=validated_data.get('name'))
        instance = Book.objects.create(**validated_data)
        return instance
ser.py

  删除数据

在BookVIew类中添加

re_path('books/(?P<pk>\d+)', views.BookView.as_view()),
from rest_framework.views import APIView
from app01.models import Book
from app01.ser import BookSerializer
from rest_framework.response import Response  # drf提供的响应对象

class BookView(APIView):
    def delete(self,request,pk):
        ret=Book.objects.filter(pk=pk).delete()
        return Response({'status':100,'msg':'删除成功'})
views.py

MoselSerializer序列化器(类模型序列化器)

  基本使用

1、在models.py中创建一张表

class Book(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=64)
models.py

2、写一个序列化的类,继承ModelSerializer

from rest_framework import serializers
from app01.models import Book

class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book  # 对应上models.py中的模型
        # fields = '__all__'  # 序列化所有的字段
        # fields = ('name','price')  # 只序列化指定的字段
        exclude = ('name',)  # 跟fields不能都写,且必须加上逗号,元组内写什么字段,则排除什么字段
ser.py

3、匹配好对应的路由

path('books2/', views.BooksView2.as_view())
urls.py

4、在视图类中使用,导入对应的模块,实例化得到序列化类的对象,把要序列化的对象传入

from rest_framework.views import APIView
from app01.models import Book
from app01.ser import BookSerializer,BookModelSerializer
from rest_framework.response import Response

class BooksView2(APIView):
    def get(self,request):
        response_msg = {'status':100,'msg':'成功'}
        book = Book.objects.all().first()
        books = Book.objects.all()
        book_ser = BookModelSerializer(book)
        books_ser = BookModelSerializer(books,many=True)
        print(type(book_ser))  # <class 'app01.ser.BookModelSerializer'>
        print(type(books_ser))  # <class 'rest_framework.serializers.ListSerializer'>
        response_msg['data'] = books_ser.data
        return Response(response_msg)
views.py

  模型序列化器的使用详解

 第一步:指定模型类

class BookModelSerializer(serializers.ModelSerializer):
 
    class Meta:
        model = Book  # 指定生成字段的模型类
fields = ('name','author') # 指定模型类中的字段

 第二步:使用fields属性

1、fields = ('btitle', 'bread')  # 指定模型类中的字段

2、fields = '__all__'  # 生成模型类中的所有字段

3、exclude =('price',)  # 取反操作,除了这个字段外的其他字段都生成

验证方法:

python manage.py shell 进入django交互环境(如果修改了,先要看修改结果,需要重新退出进入python manage.py shell)

 第三步:修改字段限制

1、显示指明字段

2、使用extra_kwargs(可以对已有的字段进行修改,或者新增没有的字段校验)

Serializer高级用法

from django.db import models

class Book(models.Model):
    title=models.CharField(max_length=32)
    price=models.BigIntegerField()
    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(self):
        return 'yuanxiaojiang is beautiful'

class Publish(models.Model):
    name=models.CharField(max_length=32)
    email=models.EmailField()
    # def __str__(self):
    #     return self.name+'ccccc'

class Author(models.Model):
    name=models.CharField(max_length=32)
    age=models.BigIntegerField()
    def __str__(self):
        return self.name
models.py
from rest_framework import serializers

class BookSerializer(serializers.Serializer):
    title111 = serializers.CharField(source='title')  # 可以改字段的名字
    price = serializers.CharField()
    pub_date = serializers.CharField()
    publish = serializers.CharField(source='publish.email')  # 可以跨表
    book_func = serializers.CharField(source='test')  # 可以执行表中的方法
    author = serializers.SerializerMethodField()
    def get_author(self,instance):
        print('instance:',instance,type(instance))
        authors = instance.authors.all()  # 取出所有作者
        ll = []
        for author in authors:
            ll.append({'name':author.name,'age':author.age})
        return ll
ser.py
from django.urls import path,re_path
from app02 import views
# 此处使用了路由分发

urlpatterns = [
    re_path('books/(?P<pk>\d+)',views.APP02BookView.as_view())
]
urls.py
from rest_framework.views import APIView
from app02.models import Book
from app02.ser import BookSerializer
from rest_framework.response import Response

class APP02BookView(APIView):
    def get(self,request,pk):
        # print(type(pk))  # <class 'str'>
        book = Book.objects.filter(id=pk).first()
        print(book)
        book_ser = BookSerializer(book)
        return Response(book_ser.data)
views.py
注意:需要使用mysql数据库,因为sqlite对日期数据不敏感,会出现 “OverflowError: Python int too large to convert to C long” 报错

  source的使用

# 1、可以改字段名字  xxx=serializers.CharField(source='title')
# 2、可以.跨表publish=serializers.CharField(source='publish.email')
# 3、可以执行方法book_func=serializers.CharField(source='test') test是Book表模型中的方法

  SerializerMethodField()的使用

# 需要有个配套方法,方法名叫get_字段名,返回值就是要显示的东西

author = serializers.SerializerMethodField()
def get_author(self,instance):
    # instance就是Book对象
    authors = instance.authors.all()  # 取出所有作者
    ll = []
    for author in authors:
        ll.append({'name':author.name,'age':author.age})
    return ll

源码分析

  many=True的实际用途

# 序列化多条数据,需要传入many=True
book_ser = BookModelSerializer(book)
books_ser = BookModelSerializer(books,many=True)
print(type(book_ser))  # <class 'app01.ser.BookModelSerializer'>
print(type(books_ser))  # <class 'rest_framework.serializers.ListSerializer'>

# 对象的生成-->先调用类的__new__方法,生成空对象
# 对象=类名(name="yuanxiaojiang"),触发类的__init__方法
# 类的__new__方法控制对象对生成

# 出现添加many=True属性结果类型不同的核心代码
def __new__(cls, *args, **kwargs):
    if kwargs.pop('many', False):
        return cls.many_init(*args, **kwargs)
    # 没有传many=True,走下面,正常的对象实例化
    return super().__new__(cls, *args, **kwargs)

 

posted @ 2023-05-23 00:24  猿小姜  阅读(11)  评论(0编辑  收藏  举报