二、Django REST Framework (DRF)序列化反序列化数据校验

news2024/11/25 23:24:45

参考: 

DRF 官方文档:

Serializers - Django REST framework中文站点

为什么要学DRF和什么是REST API | 大江狗的博客

上一章:

一、Django REST Framework (DRF)& RESTful 风格api_做测试的喵酱的博客-CSDN博客

下一章:

四、DRF序列化器create方法与update方法_做测试的喵酱的博客-CSDN博客

 三、DRF关联表的序列化(通过主表,查询从表数据)_做测试的喵酱的博客-CSDN博客

目录

一、DRF框架介绍 

1.1 介绍

1.2 安装与配置

二、演示数据准备

三、序列化器Serializer

3.1 序列化&反序列化

3.2 Python数据序列化

3.3 DRF中的序列化与反序列化

3.4 DRF框架中实现序列化

3.4.1 定义序列化器类

 3.4.2 序列化器字段中常用的选项(数据校验)

四、接口设计实现增删改查

4.1 定义 视图类  class StudentsView(View):  实现:

4.2 定义 视图类 class StudentsDetailView(View): 实现:

4.3 创建路由

五、序列化

5.1 应用场景:

5.2 创建序列化器类

5.3 序列化器实现 get 查询所有数据的请求

 5.4 读取单条数据,处理模型类的实例

六、反序列化

6.1 应用场景:

6.2 反序列化实现 post 创建单条数据的请求

6.2.1 获取接口请求json参数,并转化为字典

6.2.3 创建数据&数据校验

6.3 反序列化实现更新一条数据

6.4 实现删除一条数据

 七、序列化器中自定义校验提示信息 


一、DRF框架介绍 

1.1 介绍

Django REST Framework (DRF)这个神器我们可以快速开发出优秀而且规范的Web API来。Django REST framework 给Django提供了用于构建Web API 的强大而灵活的工具包, 包括:

  • 序列化器Serializer,可以高效的进行序列化与反序列化操作。
  • 认证:多种身份认证
  • 权限
  • 分页
  • 过滤
  • 限流
  • 可扩展,插件丰富
  • 提供了极为丰富的类视图、Mixin扩展类、ViewSet视图集。

1.2 安装与配置

1、安装

pip install djangorestframework

其他插件:(非必需)

pip install  markdown

2、注册应用

INSTALLED_APPS = [
        'rest_framework',
]

二、演示数据准备

1、创建子应用miaoschool,注册应用

2、创建2个模型类,班级模型类MiaoClass,学生信息模型类MiaoStudent

models.py

from django.db import models

# Create your models here.

class MiaoClass(models.Model):
    id = models.AutoField(primary_key=True, verbose_name='id', help_text='id')
    classname = models.CharField(max_length=20, verbose_name='班级名称', help_text='班级名称')
    clasleader = models.CharField(max_length=10, verbose_name='班主任姓名', help_text='班主任姓名')
    classcode = models.IntegerField(unique=True, verbose_name='班级code', help_text='班级code')
    ifopens = models.BooleanField(default=True, verbose_name='是否开学', help_text='是否开学')
    classrate = models.IntegerField( verbose_name='班费', help_text='班费')

    class Meta:
        # i.db_table指定创建的数据表名称
        db_table = 'tb_class'
        # 为当前数据表,设置中午呢描述
        verbose_name = "班级表"
        verbose_name_plural = "班级表"

class MiaoStudent(models.Model):
    sname = models.CharField(max_length=20, verbose_name='学生姓名', help_text='学生姓名')
    sgender = models.BooleanField(verbose_name='性别', help_text='性别')
    sage = models.IntegerField(verbose_name='年龄', help_text='年龄')
    sid = models.IntegerField(unique=True, verbose_name='学号', help_text='学号')
    sscore = models.IntegerField( verbose_name='成绩', help_text='成绩')
    classid = models.ForeignKey('miaoschool.MiaoClass',on_delete=models.CASCADE,verbose_name='班级id', help_text='班级id')


    class Meta:
        # i.db_table指定创建的数据表名称
        db_table = 'tb_student'
        # 为当前数据表,设置中午呢描述
        verbose_name = "学生信息表"
        verbose_name_plural = "学生信息表"

插入数据:

-- ----------------------------
-- Records of tb_class
-- ----------------------------
BEGIN;
INSERT INTO `tb_class` (`id`, `classname`, `clasleader`, `classcode`, `ifopens`, `classrate`) VALUES (1, '一班', '王老师', 1001, 1, 200);
INSERT INTO `tb_class` (`id`, `classname`, `clasleader`, `classcode`, `ifopens`, `classrate`) VALUES (2, '二班', '欧阳老师', 1006, 1, 300);
INSERT INTO `tb_class` (`id`, `classname`, `clasleader`, `classcode`, `ifopens`, `classrate`) VALUES (3, '三班', '东风老师', 1007, 1, 400);
INSERT INTO `tb_class` (`id`, `classname`, `clasleader`, `classcode`, `ifopens`, `classrate`) VALUES (4, '四班', '白腊图老师', 1011, 1, 20);
INSERT INTO `tb_class` (`id`, `classname`, `clasleader`, `classcode`, `ifopens`, `classrate`) VALUES (5, '五班', '张三丰老师老师', 1021, 1, 150);
COMMIT;

-- ----------------------------
-- Records of tb_student
-- ----------------------------
BEGIN;
INSERT INTO `tb_student` (`id`, `sname`, `sgender`, `sage`, `sid`, `sscore`, `classid_id`) VALUES (1, '阿珍', 1, 18, 101, 100, 1);
INSERT INTO `tb_student` (`id`, `sname`, `sgender`, `sage`, `sid`, `sscore`, `classid_id`) VALUES (2, '李珍', 1, 18, 104, 100, 1);
INSERT INTO `tb_student` (`id`, `sname`, `sgender`, `sage`, `sid`, `sscore`, `classid_id`) VALUES (3, '孙珍', 1, 18, 102, 100, 1);
INSERT INTO `tb_student` (`id`, `sname`, `sgender`, `sage`, `sid`, `sscore`, `classid_id`) VALUES (7, '李爱', 1, 18, 106, 100, 1);
INSERT INTO `tb_student` (`id`, `sname`, `sgender`, `sage`, `sid`, `sscore`, `classid_id`) VALUES (9, '张三', 0, 18, 2301, 20, 2);
INSERT INTO `tb_student` (`id`, `sname`, `sgender`, `sage`, `sid`, `sscore`, `classid_id`) VALUES (10, '李爱', 1, 18, 107, 100, 1);
INSERT INTO `tb_student` (`id`, `sname`, `sgender`, `sage`, `sid`, `sscore`, `classid_id`) VALUES (11, '张三', 0, 18, 2302, 20, 2);
INSERT INTO `tb_student` (`id`, `sname`, `sgender`, `sage`, `sid`, `sscore`, `classid_id`) VALUES (12, '李三', 1, 19, 2325, 30, 2);
INSERT INTO `tb_student` (`id`, `sname`, `sgender`, `sage`, `sid`, `sscore`, `classid_id`) VALUES (13, '张红', 0, 20, 2303, 40, 2);
INSERT INTO `tb_student` (`id`, `sname`, `sgender`, `sage`, `sid`, `sscore`, `classid_id`) VALUES (14, '张珍', 1, 16, 2304, 50, 3);
INSERT INTO `tb_student` (`id`, `sname`, `sgender`, `sage`, `sid`, `sscore`, `classid_id`) VALUES (15, '刘慧珍', 0, 17, 2305, 60, 3);
INSERT INTO `tb_student` (`id`, `sname`, `sgender`, `sage`, `sid`, `sscore`, `classid_id`) VALUES (16, '王莫涵', 1, 18, 2306, 70, 3);
INSERT INTO `tb_student` (`id`, `sname`, `sgender`, `sage`, `sid`, `sscore`, `classid_id`) VALUES (17, '张茜茜', 0, 20, 2307, 80, 4);
INSERT INTO `tb_student` (`id`, `sname`, `sgender`, `sage`, `sid`, `sscore`, `classid_id`) VALUES (18, '学姐', 1, 15, 2308, 90, 4);
INSERT INTO `tb_student` (`id`, `sname`, `sgender`, `sage`, `sid`, `sscore`, `classid_id`) VALUES (19, '张绍京', 0, 14, 2309, 100, 4);
INSERT INTO `tb_student` (`id`, `sname`, `sgender`, `sage`, `sid`, `sscore`, `classid_id`) VALUES (20, '董超', 1, 20, 2311, 20, 5);
INSERT INTO `tb_student` (`id`, `sname`, `sgender`, `sage`, `sid`, `sscore`, `classid_id`) VALUES (21, '吕布', 0, 21, 2321, 40, 5);
INSERT INTO `tb_student` (`id`, `sname`, `sgender`, `sage`, `sid`, `sscore`, `classid_id`) VALUES (22, '黄大仙', 1, 17, 2322, 60, 5);
COMMIT;

 

三、序列化器Serializer

3.1 序列化&反序列化

每种编程语言都有各自的数据类型, 将属于自己语言的数据类型或对象转换为可通过网络传输或可以存储到本地磁盘的数据格式(如:XML、JSON或特定格式的字节串)的过程称为序列化(seralization);反之则称为反序列化。

API开发的本质就是各种后端语言的自己的数据类型序列化为通用的可读可传输的数据格式,比如常见的JSON类型数据。

3.2 Python数据序列化

举个简单例子。Python自带json模块的dumps方法可以将python常用数据格式(比如列表或字典)转化为json格式,如下所示。你注意到了吗? 生成的json格式数据外面都加了单引号,这说明dict类型数据已经转化成了json字符串。

>>> import json
>>> json.dumps({"name":"John", "score": 112})
'{"name": "John", "score": 112}'

3.3 DRF中的序列化与反序列化

序列化: 将 查询集QuerySet (多个模型类的集合)与单个模型类的实例,通过序列化器转化为 json数据(字符串)。

反序列化:将json格式的字符串数据,通过序列化器转换为Django中的模型类的对象。

3.4 DRF框架中实现序列化

1、在应用中,创建一个名为 serializers.py 的文件。(推荐命名为serializers.py,其他命名也可以)

3.4.1 定义序列化器类

1、定义序列化器类,必须得继承Serializer类或者Serializer子类

from rest_framework import serializers
class StudentSerializer(serializers.Serializer):

2、定义的序列化器类中,字段名要与模型类中的字段名保持一致。(字段个数可以不一致,但是字段名称一定要保持一致)
3、定义的序列化器类的字段(类属性)为Field子类

4、序列化器类中,定义了哪些字段,在序列化与反序列化中,只处理这些定义的字段,其他字段不处理。

 5.常用的序列化器字段类型。

跟模型类差不多

数据类型Field类型
intIntegerField
strCharField
boolBooleanField
datetimeDateTimeField

6、序列化器字段中常用的选项

a、  label和help_text,与模型类中的verbose_name和help_text参数一样

b、(用于数据校验) IntegerField,可以使用max_value指定最大值,min_value指定最小值

c、 (用于数据校验)CharField,可以使用max_length指定最大长度,min_length指定最小长度

d、定义的序列化器字段中,required模式为True,既在序列化或者反序列化中,都必须处理该字段。 如果想要设置某一个字段为非必填,required=False 就可以了

如:

clasleader = models.CharField(max_length=10, verbose_name='班主任姓名', help_text='班主任姓名',required=False)


     

 3.4.2 序列化器字段中常用的选项(数据校验)

关键字名称作用
label和help_text与模型类中的verbose_name和help_text参数一样。做备注用的
max_value指定最大值
min_value指定最小值
max_length指定最大长度
min_length指定最小长度
required=False设置某一个字段为非必填
allow_null=True这个字段允许传null
write_only=True(常用)只在反序列化的时候,处理该被装饰的字段
read_only=True(常用)只在序列化的时候,处理该被装饰的字段
allow_blank=True允许该字符串字段的值为空(只有CharField才有这个关键词)
default=“xx"在序列化/反序列化时,如该字段没有传值,则使用xx默认值
format='%Y年%m月%d日 %H:%M:%S'
DateTimeField可以使用format参数指定格式化字符串。如

a、  label和help_text,与模型类中的verbose_name和help_text参数一样

b、(用于数据校验) IntegerField,可以使用max_value指定最大值,min_value指定最小值

c、 (用于数据校验)CharField,可以使用max_length指定最大长度,min_length指定最小长度

d、设置某一个字段为非必填,required=False 就可以了(好像有的版本没有这个关键字)

e、allow_null=True,这个字段允许传null

f、write_only=True(常用),只在反序列化的时候,处理该被装饰的字段。该字段只在反序列化输入的时候,做数据校验处理,在序列化输出的时候不做输出。write_only默认为False

举个例子:

用户注册账号的场景,注册成功后,会回显用户注册时的手机号等信息,但是不会回显密码。

将密码属性设置为write_only=True

password = models.CharField(max_length=10, verbose_name='班主任姓名', help_text='班主任姓名',write_only=True)

用户输入的json格式的字符串数据,通过序列化器转换为Django中的模型类的对象(反序列化),对password进行校验。

但是将模型类通过序列化器转换为json数据时(序列化)不显示password数据。

g、read_only=True(常用),只在序列化的时候,处理该被装饰的字段。

创建班级时,会自动生成一个班级id。在用户输入的json格式的字符串数据,通过序列化器转换为Django中的模型类的对象(反序列化),不会对id进行校验。

创建成功后,要给用户回显生成的id。将模型类通过序列化器转换为json数据时(序列化)显示id数据。
     

四、接口设计实现增删改查

通过视图类,来实现增删改查的接口。

4.1 定义 视图类  class StudentsView(View):  实现:

1、get 查询所有数据的请求

GET /students/

步骤:

  1. 数据库操作,(ORM),读取所有数据的实例 
  2. 序列化输出,将查询集QuerySet 转换为json数据类型

2、post 创建单条数据的请求。

POST /students/  新的学生数据以json的形式来传递

步骤:

  1. 对用户输入的json数据进行校验(json转字典 )
  2. 反序列化操作,将字典格式的数据,转成序列化器的对象。
  3. 序列化器对数据校验
  4. 用序列化器的数据,去操作数据库,创建数据
  5. 数据回显,序列化输出操作。将模型对象转换为json数据

4.2 定义 视图类 class StudentsDetailView(View): 实现:

1、获取1条数据的接口,获取数据详情

GET /students/<int:pk>/

 步骤:

  1. 对用户传参做校验。校验pk(主键)的值是否存在数据
  2. ORM框架,读取一条数据
  3. 序列化输出,将模型类的实例,转化为json

2、更新1条数据的接口

PUT /students/<int:pk>/

传参为json 

步骤:

  1. 数据校验
  2. 反序列化操作,将json数据转化为序列化器的实例
  3. 数据库操作,更新数据
  4. 数据回显,序列化输出,将模型类转换为json数据

3、删除一条数据的接口

DELETE /studentss/<int:pk>/

步骤: 

  1. 数据校验
  2. 数据库操作,删除一条数据

4.3 创建路由

from miaoschool import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path("students/",views.StudentsView.as_view()),
    path('students/<int:pk>/',views.StudentsDetailView.as_view()),

五、序列化

5.1 应用场景:

序列化

将 从数据库中读取到的数据QuerySet实例,转换为 序列化器的实例

场景:

用户请求数据,从数据库取出数据,反给用户。ORM框架,从数据库中取的数据是QuerySet。

通过序列化将QuerySet 转化为序列化器的实例,再转化为josn数据返回给用户。

实现接口:

1、get 查询所有数据的请求

GET /students/

 2、获取1条数据的接口,获取数据详情

GET /students/<int:pk>/

5.2 创建序列化器类

序列化器类,字段与模型类字段基本一致,用来做将模型类实例与json数据相互转换的中间件。

serializers.py 

# -*- coding:utf-8 -*-
# @Author: 喵酱
# @time: 2023 - 05 -21
# @File: serializers.py
# desc: 序列化器
from rest_framework import serializers

class StudentSerializer(serializers.Serializer):

    id = serializers.IntegerField(label='学生id', help_text='学生id', max_value=1000, min_value=1)
    sname = serializers.CharField(label='学生姓名', help_text='学生姓名',max_length=10,min_length=1 )
    sgender =serializers.BooleanField(label='学生性别', help_text='学生性别',)
    sage = serializers.IntegerField(label='学生年龄', help_text='学生年龄',max_value=100, min_value=1)
    sid = serializers.IntegerField(label='学生学号', help_text='学生学号',)
    sscore = serializers.IntegerField(label='学生成绩', help_text='学生成绩', max_value=100, min_value=0)
    # 注意,转换外键的值时,输入使用类属性名称来转化,接收到的是一个主表的实例对象
    classid = serializers.CharField(label='班级id', help_text='班级id',)
    # 注意,转换外键的值时,输入使用从表中外键的值来转化,接收到的是一个真正的数值
    classid_id = serializers.IntegerField(label='班级id', help_text='班级id', max_value=10, min_value=1)

 注意外键的处理:

    # 注意,转换外键的值时,输入使用类属性名称来转化,接收到的是一个主表的实例对象
    classid = serializers.CharField(label='班级id', help_text='班级id',)
    # 注意,转换外键的值时,输入使用从表中外键的值来转化,接收到的是一个真正的数值
    classid_id = serializers.IntegerField(label='班级id', help_text='班级id', max_value=10, min_value=1)

5.3 序列化器实现 get 查询所有数据的请求

一、视图函数的处理。

步骤:

  1. 数据库操作,(ORM),读取所有数据的实例 
  2. 序列化输出,将查询集QuerySet 转换为json数据类型
class StudentsView(View):

    # 查询所有数据
    def get(self,request):
        # 获取列表数据
        queryset = MiaoStudent.objects.all()
        print(queryset)
        serializer = StudentSerializer(instance=queryset, many=True)
        return JsonResponse(serializer.data, safe=False)

注意:

1、 QuerySet 是多个模型类实例的集合。返回给用户的数据格式不是json,而是一个列表,每个元素是一个json。

2、处理QuerySet,一定要使用many=True

serializer = StudentSerializer(instance=queryset, many=True)

3、将序列化对象实例,转化为json的列表。

serializer.data 是序列化后的数据

JsonResponse(serializer.data, safe=False)

二、请求返回数据

[
    {
        "id": 1,
        "sname": "阿珍",
        "sgender": true,
        "sage": 18,
        "sid": 101,
        "sscore": 100,
        "classid": "MiaoClass object (1)",
        "classid_id": 1
    },
    {
        "id": 2,
        "sname": "李珍",
        "sgender": true,
        "sage": 18,
        "sid": 104,
        "sscore": 100,
        "classid": "MiaoClass object (1)",
        "classid_id": 1
    },
   
]

 5.4 读取单条数据,处理模型类的实例

 获取1条数据的接口,获取数据详情

GET /students/<int:pk>/

 步骤:

  1. 对用户传参做校验。校验pk(主键)的值是否存在数据
  2. ORM框架,读取一条数据
  3. 序列化输出,将模型类的实例,转化为json

一、视图函数的处理。

class StudentsDetailView(View):
    def get(self, request, pk):
        # 1、需要校验pk在数据库中是否存在

        # 2、从数据库中读取项目数据
        try:
            student_obj = MiaoStudent.objects.get(id=pk)
        except Exception as e:
            return JsonResponse({'msg': '参数有误'}, status=400)
        serializer = StudentSerializer(instance=student_obj)

        return JsonResponse(serializer.data)

注意:

student_obj是一个模型类的实例。

将模型类的实例,序列化

serializer = StudentSerializer(instance=student_obj)

 serializer.data 是序列化后的数据

将序列化对象实例,转化为json的数据。

JsonResponse(serializer.data, safe=False)

六、反序列化

6.1 应用场景:

用户传入json请求数据,先将用户传入的json 字符串,转为字典,再将这个字典反序列化转化为模型类的实例,然后再调用ORM框架,执行sql。

比如创建学生信息,用户输入一个json,然后将这个json生成一行表的数据。

实现接口:

 1、post 创建单条数据的请求。

POST /students/  新的学生数据以json的形式来传递

 2、更新1条数据的接口

PUT /students/<int:pk>/

 3、删除一条数据的接口

DELETE /studentss/<int:pk>/

6.2 反序列化实现 post 创建单条数据的请求

 post 创建单条数据的请求。

POST /students/  新的学生数据以json的形式来传递

步骤:

  1. 对用户输入的json数据进行校验(json转字典 )
  2. 反序列化操作,将字典格式的数据,转成序列化器的对象。
  3. 序列化器对数据校验
  4. 用序列化器的数据,去操作数据库,创建数据
  5. 数据回显,序列化输出操作。将模型对象转换为json数据

class StudentsView(View) 下的方法: 

    # 创建数据
    def post(self, request):
        # 1、获取json参数并转化为python中的数据类型(字典)
        try:
            dic_data = json.loads(request.body)
        except Exception as e:
            return JsonResponse({'msg': '参数有误'}, status=400)
        # 获取反序列化的实例对象
        student_obj = StudentSerializer(data=dic_data)
        # 对数据进行校验
        # 校验不通过
        if not student_obj.is_valid():
            return JsonResponse(student_obj.errors, status=400)
        # 创建数据,执行saql
        student=MiaoStudent.objects.create(**student_obj.validated_data)

        # 对创建的数据进行数据回显(序列化)
        serializer = StudentSerializer(instance=student)
        return JsonResponse(serializer.data, status=201)

6.2.1 获取接口请求json参数,并转化为字典

1、获取接口请求json参数,并转化为字典。

我们手动对输入数据做一次简单的校验,是否能转成字典

def get_json(request):
    try:
        # 1、获取接口请求json参数,并转化为字典
        data = json.loads(request.body)
    except Exception as e:
        return JsonResponse({"msg":"参数有误"},status=400)

6.2.3 创建数据&数据校验

序列化器提供了数据校验功能。

定义序列化器类,使用data关键字参数传递字典参数。

1、序列化器类:

在创建序列化器类时,如

sscore = serializers.IntegerField(label='学生成绩', help_text='学生成绩', max_value=100, min_value=0)

指定了sscore字段的校验规则,大于等于0,小于等于100。

sname = serializers.CharField(label='学生姓名', help_text='学生姓名',max_length=10,min_length=1 )

指定了sname字段的校验规则,最少1个字符,最多10个字符。

2、调用校验功能:

序列化器对象调用.is_valid()方法,才会开始对前端输入的参数进行校验

# 获取反序列化的实例对象
student_obj=StudentSerializer(data=dic_data)

调用校验方法

student_obj.is_valid()

返回值为布尔类型,校验通过为True,校验失败为False。

3、获取校验失败的报错信息:

.只有在调用.is_valid()方法之后,才可以使用序列化器对象调用.errors属性,来获取错误提示信息(字典类型)

只有在调用

student_obj.is_valid()

校验之后,才可以查看报错信息,不然报错。

查看报错信息

student_obj.errors

4、在校验不通过时,直接抛出异常。

调用.is_valid()方法,添加raise_exeception=True,校验不通过会抛出异常。

student_obj.is_valid(raise_exeception=True)

5、校验之后的数据.validated_data

student_obj.validated_data

只有在调用.is_valid()方法之后,才可以使用序列化器对象调用.validated_data属性,来获取校验通过之后的数据。

.validated_data 数据与 使用json.load转化之后的数据有区别

6、整体代码:


    # 创建数据
    def post(self, request):
        # 1、获取json参数并转化为python中的数据类型(字典)
        try:
            python_data = json.loads(request.body)
        except Exception as e:
            return JsonResponse({'msg': '参数有误'}, status=400)
        # 获取反序列化的实例对象
        student_obj = StudentSerializer(data=data)
        # 对数据进行校验
        # 校验不通过
        if not student_obj.is_valid():
            return JsonResponse(student_obj.errors, status=400)
        # 创建数据,执行saql
        student=MiaoStudent.objects.create(**student_obj.validated_data)

        # 对创建的数据进行数据回显(序列化)
        serializer = StudentSerializer(instance=student)
        return JsonResponse(serializer.data, status=201)

7、功能演示

a、传入sscore大于100的数字

http://127.0.0.1:8000/students/

参数:

{
    "sname":"浩轩",
    "sgender":1,
    "sage":17,
    "sid":2046,
    "sscore":101,
    "id":26,
    "classid_id":3

}

返回结果:

{
    "sscore": [
        "Ensure this value is less than or equal to 100."
    ]
}

b、传入ssname长度为11位字符

传参:

{
    "sname":"浩哈哈哈哈哈哈哈哈哈哈哈哈哈哈轩",
    "sgender":1,
    "sage":17,
    "sid":2046,
    "sscore":101,
    "id":26,
    "classid_id":3

}

返回结果:

{
    "sname": [
        "Ensure this field has no more than 10 characters."
    ],
    "sscore": [
        "Ensure this value is less than or equal to 100."
    ]
}

疑问:

为啥我的提示是英文?明天查查。

c、正常创建数据

6.3 反序列化实现更新一条数据

更新1条数据的接口

PUT /students/<int:pk>/

传参为json 

步骤:

  1. 数据校验
  2. 反序列化操作,将json数据转化为序列化器的实例
  3. 数据库操作,更新数据
  4. 数据回显,序列化输出,将模型类转换为json数据

  def put(self, request, pk):
        # 1、需要校验pk在数据库中是否存在
        # 2、从数据库中读取项目数据
        try:
            student_obj = MiaoStudent.objects.get(id=pk)
        except Exception as e:
            return JsonResponse({'msg': '参数有误'}, status=400)

        # 3、获取json参数并转化为字典
        try:
            dic = json.loads(request.body)
        except Exception as e:
            return JsonResponse({'msg': '参数有误'}, status=400)

        # 4、序列化,将 用户输入的字典,转化为序列化实例
        serializer_obj=StudentSerializer(data=dic)
        # 5、序列化器对用户传入的参数进行校验
        # is_valid() 数据校验
        # serializer_obj.errors 校验后报错信息
        if not serializer_obj.is_valid():
            return JsonResponse(serializer_obj.errors, status=400)

        # 6、更新数据,操作数据库
        student_obj.sname = serializer_obj.validated_data.get('sname')
        student_obj.sgender = serializer_obj.validated_data.get('sgender')
        student_obj.sid = serializer_obj.validated_data.get('sid')
        student_obj.sscore = serializer_obj.validated_data.get('sscore')
        student_obj.classid_id = serializer_obj.validated_data.get('classid_id')
        student_obj.save()

        # 7、数据回显示(非必需的)。将读取的项目数据转化为字典
        serializer = StudentSerializer(instance=student_obj)
        return JsonResponse(serializer.data, status=201)

接口演示:

1、使用put请求

2、http://127.0.0.1:8000/students/1/

3、参数

{
    "sname":"阿珍二号",
    "sgender":1,
    "sage":17,
    "sid":101,
    "sscore":100,
    "id":26,
    "classid_id":3

}

6.4 实现删除一条数据

 删除一条数据的接口

DELETE /studentss/<int:pk>/

步骤: 

  1. 数据校验
  2. 数据库操作,删除一条数据
    def delete(self, request, pk):
        # 1、需要校验pk在数据库中是否存在

        # 2、读取主键为pk的项目数据
        try:
            project_obj = MiaoStudent.objects.get(id=pk)
        except Exception as e:
            return JsonResponse({'msg': '参数有误'}, status=400)

        # 3、执行删除
        project_obj.delete()

        return JsonResponse({'msg': '删除成功'}, status=204)

 七、序列化器中自定义校验提示信息 

1、修改语言与时区

setting.py 

简体中文

LANGUAGE_CODE = 'zh-hans' 

TIME_ZONE = 'Asia/Shanghai'

2、序列化器中自定义校验提示信息 

    sage = serializers.IntegerField(label='学生年龄', help_text='学生年龄',max_value=100, min_value=1,
                                    error_messages = {
                                        'max_value': '学生年龄不能超过100岁',
                                        'min_value':'学生年龄不能小于1岁'
                                    })

通过关键字 error_messages = {} 实现

字典中,key为定义校验字段的值,value是自定义的提示。

八、数据其他类型的校验 validators=[]

validators=[]

列表中,可以设置多种校验规则,如唯一约束校验,字符串内容校验

8.1 唯一约束校验

模版:

validators=[UniqueValidator(queryset=MiaoStudent.objects.all(),message='学生id不能重复')])

1、validators=[] 在列表里面,设置多种校验规则

2、UniqueValidator 校验器,drf框架自带。

from rest_framework.validators import UniqueValidator

3、UniqueValidator(queryset=MiaoStudent.objects.all(),message='学生id不能重复')

UniqueValidato:唯一约束校验

queryset=指定查询集(字段,在哪个查询集里面唯一校验)

message= 报错提示

8.1.1 例子:创建学生校验

序列化器类

class StudentSerializer(serializers.Serializer):

    id = serializers.IntegerField(label='学生id', help_text='学生id', max_value=1000, min_value=1,
                                  validators=[UniqueValidator(queryset=MiaoStudent.objects.all(),message='学生id不能重复')])
    sname = serializers.CharField(label='学生姓名', help_text='学生姓名',max_length=10,min_length=1 )
    sgender =serializers.BooleanField(label='学生性别', help_text='学生性别',)
    sage = serializers.IntegerField(label='学生年龄', help_text='学生年龄',max_value=100, min_value=1,
                                    error_messages = {
                                        'max_value': '学生年龄不能超过100岁',
                                        'min_value':'学生年龄不能小于1岁'
                                    })
    sid = serializers.IntegerField(label='学生学号', help_text='学生学号',)
    sscore = serializers.IntegerField(label='学生成绩', help_text='学生成绩', max_value=100, min_value=0)
    # 注意,转换外键的值时,输入使用类属性名称来转化,接收到的是一个主表的实例对象
    # classid = serializers.CharField(label='班级id', help_text='班级id',)
    # 注意,转换外键的值时,输入使用从表中外键的值来转化,接收到的是一个真正的数值
    classid_id = serializers.IntegerField(label='班级id', help_text='班级id', max_value=10, min_value=1)

接口请求:

 8.1.2  例子:创建班级校验

class ClassSerializer(serializers.Serializer):
    id = serializers.IntegerField(label='班级id', help_text='班级id')
    classname = serializers.CharField(label='班级名称',
                                      help_text='班级名称',
                                      max_length=20,
                                      min_length=2,
                                      error_messages={
                                          'max_length': '班级名称不能超过20个字',
                                          'min_length': '班级名称不能小于2个字'
                                      },
                                      validators=[UniqueValidator(queryset=MiaoClass.objects.all(),message='班级名称不能重复')]

                                     )

 8.2 自定义校验规则函数

实现功能:

实现一个自定义校验规则的函数。在进行校验时,调用我们这个函数

8.2.1 自定义外部校验函数

1、定义校验方法

def check_class_name(classname:str):
    if not classname.endswith("班"):
        raise serializers.ValidationError("classname必须以'班'结尾")

注意:

  1. 必须抛出异常
  2. 没有要求return ture false

2、序列化器中,调用校验方法

在 validators=[check_class_name] 中,调用。注意函数名后没有小括号

class ClassSerializer(serializers.Serializer):
    id = serializers.IntegerField(label='班级id', help_text='班级id')
    classname = serializers.CharField(label='班级名称',
                                      help_text='班级名称',
                                      max_length=20,
                                      min_length=2,
                                      error_messages={
                                          'max_length': '班级名称不能超过20个字',
                                          'min_length': '班级名称不能小于2个字'
                                      },
                                      validators=[UniqueValidator(queryset=MiaoClass.objects.all(),message='班级名称不能重复'),
                                                  check_class_name]

                                     )

8.2.2 自定义序列化器内部的校验函数

1、可以在序列化器类中对单个字段进行校验。在序列化器类中,定义校验方法函数

2、校验函数的命名:

  1. 必须以validate_开头
  2. 后面跟上字段名。与模型类的属性名称保持一致。
  3. 如果校验不通过,必须得返回serializers.ValidationError('具体报错信息')异常
  4. 如果校验通过,往往需要将校验之后的值,返回
  5. 如果该字段在定义时添加的校验规则不通过,那么是不会调用单字段的校验方法
     

对classname 字段的校验,定义函数如下:

    def validate_classname(self, classname: str):
        if not classname.endswith('班'):
            raise serializers.ValidationError('班级名称,必须以班结尾')
        return classname

3、定义完函数,不需要手动调用。


class ClassSerializer(serializers.Serializer):
    id = serializers.IntegerField(label='班级id', help_text='班级id')
    classname = serializers.CharField(label='班级名称',
                                      help_text='班级名称',
                                      max_length=20,
                                      min_length=2,
                                      error_messages={
                                          'max_length': '班级名称不能超过20个字',
                                          'min_length': '班级名称不能小于2个字'
                                      },
                                      # validators=[UniqueValidator(queryset=MiaoClass.objects.all(),message='班级名称不能重复'),
                                      #             check_class_name],
                                      validators=[UniqueValidator(queryset=MiaoClass.objects.all(), message='班级名称不能重复'),
                                                 ]

                                     )
    clasleader = serializers.CharField(max_length=10, label='班主任姓名', help_text='班主任姓名')
    classcode = serializers.IntegerField(label='班级code', help_text='班级code')
    ifopens = serializers.BooleanField(label='是否开学', help_text='是否开学')
    classrate = serializers.IntegerField(label='班费', help_text='班费')
    # miaostudent_set = serializers.PrimaryKeyRelatedField(label='学生id', help_text='学生id',read_only=True,many=True)
    # sid = serializers.PrimaryKeyRelatedField(label='学生id', help_text='学生id', read_only=True, many=True)
    # sid = serializers.PrimaryKeyRelatedField(label='学生id', help_text='学生id',
    #                                          queryset = MiaoStudent.objects.all(),
    #                                          write_only=True,
    #                                          many=True)
    # sid = serializers.StringRelatedField(many=True)
    # sid = serializers.SlugRelatedField(slug_field='sname',many=True,queryset=MiaoStudent.objects.all())
    # sid = serializers.SlugRelatedField(slug_field='sname', many=True, read_only=True)
    miaostudent_set = StudentINfoSerializer(read_only=True,many=True)

    def validate_classname(self, classname: str):
        if not classname.endswith('班'):
            raise serializers.ValidationError('班级名称,必须以班结尾')
        return classname

九、多字段联合校验

    # 1、可以在序列化器类中对多个字段进行联合校验
    # 2、使用固定的validate方法,会接收上面校验通过之后的字典数据
    # 3、当所有字段定义时添加的校验规则都通过,且每个字段的单字段校验方法通过的情况下,才会调用validate
    def validate(self, attrs: dict):
        if len(attrs.get('leader')) <= 4 or not attrs.get('is_execute'):
            raise serializers.ValidationError('项目负责人名称长度不能少于4位或者is_execute参数为False')
        return attrs

十、to_internal_value 

 def to_internal_value(self, data):
        # 1、to_internal_value方法,是所有字段开始进行校验时入口方法(最先调用的方法)
        # 2、会依次对序列化器类的各个序列化器字段进行校验:
        #   对字段类型进行校验 -> 依次验证validators列表中的校验规则 -> 从右到左依次验证其他规则 -> 调用单字段校验方法
        #    to_internal_value调用结束 -> 调用多字段联合校验方法validate方法
        tmp = super().to_internal_value(data)
        # 对各个单字段校验结束之后的数据进行修改
        return tmp

十一、to_representation

 def to_representation(self, instance):
        # 1、to_representation方法,是所有字段开始进行序列化输出时的入口方法(最先调用的方法)
        tmp =super().to_representation(instance)
        return tmp

十二、字段校验规则的顺序

字段校验,有多种方式,顺序是:

依次验证validators列表中的校验规则 -> 从右到左依次验证其他规则 -> 调用单字段校验方法-> 调用多字段联合校验方法validate方法
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/566244.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++】类和对象(中上):类的六个默认成员函数——构造函数、析构函数、拷贝构造函数!

目录 前言&#xff1a; 一、类的默认成员函数&#xff1a; 二、构造函数&#xff1a; 1.特性&#xff1a; 构造函数调用规则&#xff1a; 1.无参数的构造函数&#xff08;默认构造函数&#xff09;&#xff1a; 2.带参数的构造函数&#xff1a; 3.全缺省的构造函数&…

Qt编写视频监控系统75-计算实时码率并显示

一、前言 做监控摄像头的实时视频显示&#xff0c;一般还会要求统计实时码率显示在通道画面上&#xff0c;一个是为了测试下整个软件的性能&#xff0c;同时也看下当前到底是主码流还是子码流&#xff0c;设备到底是不是真的按照设定的码流大小来传输视频数据的。视频码率就是…

【Mysql】 数据类型

文章目录 【Mysql】 数据类型数据类型分类数值类型1. tinyint类型2. bit类型3. 小数类型 字符串类型1.char2.varchar3. 日期和时间类型4. enum 和 set 【Mysql】 数据类型 mysql中数据类型的作用&#xff1a; 约束操作者的行为更清晰的代码逻辑不同的功用 – 例如&#xff0c…

【JavaSE】Java基础语法(八)

文章目录 &#x1f353;1. 类和对象&#x1f379;&#x1f379;1.1 类和对象的关系&#x1f379;&#x1f379;1.2 类的定义 &#x1f353;2. 对象内存图&#x1f379;&#x1f379;2.1 单个对象内存图&#x1f379;&#x1f379;2.2 多个对象内存图2.3 多个对象指向相同内存图…

统计学_贾俊平——思考题第9章 分类数据分析

1&#xff0e;简述列联表的构造与列联表的分布。 答&#xff1a;列联表是将两个以上的变量进行交叉分类的频数分布表。 列联表的分布可以从两个方面看&#xff0c;一个是观察值的分布&#xff0c;又称为条件分布&#xff0c;每个具体的观察值就是条件频数&#xff1b;一个是期望…

【数据结构】树的认识

一个人的未来不是预测出来的&#xff0c;而是创造出来的。 -- 亚当詹姆斯目录 &#x1f341;前言&#xff1a; &#x1f340;一.什么是树&#xff1f; &#x1f351;二.树有什么用&#xff1f; ❤️1. 数据库 &#x1f9e1;2. 文件系统 &#x1…

chatgpt赋能python:PythonUSB摄像头-拍摄更美好的瞬间

Python USB摄像头 - 拍摄更美好的瞬间 在过去的几年中&#xff0c;摄影已经迅速成为了一种爆炸性的趋势。人们希望能够记录下人生中的美好瞬间&#xff0c;分享给全球的亲朋好友。而USB摄像头的普及与发展使得照片拍摄变得更加便利。而在这其中&#xff0c;Python也扮演了一个…

spingboot+jsp仓储型物流企业车辆运输管理系统

随着时代的进步,物流车辆运输行业也逐渐变得庞大起来。当然,物流车辆运输公司要想做大做强,就有必要有自己完整的一套物流车辆运输管理系统。这必将为物流管理公司提供规范化的管理模式,在各个部门之间有效的协调、合作过程中必将为物流车辆公司提供大量的客户生源,争取赢得最大…

6.4_7关键路径

上一节我们学的叫做AOV网&#xff08;activity on vertex&#xff09; 这一节我们是(activity on edge network) 顶点表示事件是一瞬间发生的事情。边上的权值表示完成该活动的开销。 AOE网中&#xff0c;有些事情是可以并行的。 前后活动之间存在依赖关系&#xff0c;我i们要知…

python绘制密度图

本期目录 1、绘图参数2、使用 matplotlib 库绘制密度图时常用的参数3、案例4、 运行结果python绘图往期系列文章目录 1、绘图参数 可以使用多种库来绘制密度图&#xff0c;其中最常用的是 seaborn 和 matplotlib。以下是使用 seaborn 库绘制密度图时常用的参数&#xff1a; i…

简历上,我写精通 JUC 的底气

真的假的&#xff0c;你简历上敢写精通 JUC &#xff1f; 是真学到精通了&#xff0c;还是说只学到了个皮毛就写精通&#xff0c;从而争取一个面试机会。 我相信&#xff0c;当很多人看到文章标题的第一反应也会如上面的一样&#xff0c;质疑、好奇。这很正常&#xff0c;如果…

手把手教你用Python调用彩云机器翻译API

一、引言 彩云这个小而美的机器翻译一直很低调&#xff0c;它让人眼前一亮的是之前我们分享的网页翻译插件&#xff0c;可以把外文网站翻译成英中对照的样式&#xff0c;便于我们学习。之前我们也写过文章介绍过&#xff1a; PythonFan&#xff1a;如何用Google翻译英文网页成…

c++学习——类和对象

类和对象的基本概念 类是自定义数据类型&#xff0c;是C语言的结构体进化而成的 对象是类实例化出的&#xff0c;用数据类型定义一个变量 #define _CRT_SECURE_NO_WARNINGS #include <iostream> using namespace std;class Maker //这个是类 { public:int a;//成员属性…

PostgreSQL EDB 公司推出新服务,ORACLE 平移到 POSTGRESQL 一体化服务

开头还是介绍一下群&#xff0c;如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;在新加的朋友会分到2群&#xff08;共…

创建本地LocalHost-SSL证书

mkcert 使用方法 mkcert 是一个开源工具&#xff0c;用于快速生成有效的本地开发证书。它可以帮助开发人员在本地环境中使用 HTTPS 加密来模拟真实的生产环境。 安装 首先&#xff0c;你需要安装 mkcert 工具。以下是在常见操作系统上安装的命令&#xff1a; macOS 使用 Homebr…

集简云数据表无需代码连接抖音的方法

使用场景 抖音作为自媒体时代的主流平台&#xff0c;越来越多的企业选择通过短视频来推广自己的产品或者吸引更多粉丝。那么随时关注抖音视频下的评论&#xff0c;了解用户的想法和需求&#xff0c;并针对不同的评论提供更好的回应是每一位运营的重点工作之一&#xff0c;但是运…

利用 PRIMO 重构 M87 黑洞图像,普林斯顿高等研究院成功将「甜甜圈」变身「金戒指」...

By 超神经 内容一览&#xff1a;2019 年&#xff0c;「事件视界望远镜 (Event Horizon Telescope&#xff0c;简称 EHT)」全球研究团队发布了人类历史上第一张黑洞照片&#xff0c;受限于当时的观测条件&#xff0c;这张黑洞图像只呈现出一个模糊不清的轮廓。近日&#xff0c;天…

研发工程师玩转Kubernetes——自动扩缩容

在《研发工程师玩转Kubernetes——使用Deployment进行多副本维护》一文中&#xff0c;我们通过Deployment实现了多副本维护——即维持在一个确定数量的副本个数。而在现实场景中&#xff0c;我们往往需要根据服务的压力&#xff0c;采用水平&#xff08;横向&#xff09;扩容的…

分享给你这几款冷门好用的工具

分享一&#xff1a;Hi HiSlide Hi HiSlide是一个在线演示文稿制作工具&#xff0c;它可以帮助用户轻松地创建出色的演示文稿。以下是该网站的一些功能和特点&#xff1a; 多种模板选择**&#xff1a;Hi HiSlide提供了多种演示文稿模板&#xff0c;适合不同行业和场合的演示需…

chatgpt赋能python:Python%.6f:一门强大且易于学习的编程语言

Python%.6f&#xff1a;一门强大且易于学习的编程语言 Python是一门免费开源的高级编程语言&#xff0c;用于快速开发脚本、Web应用、科学计算、数据分析、人工智能等应用程序。Python的灵活性、易学性、可读性和强大的第三方库使其成为全球最受欢迎的编程语言之一。 Python的…