【5.0】DRF之序列化组件
【一】序列化组件介绍
- 做序列化
- 做反序列化
- 在反序列化保存到数据库之前,做数据库校验
【1】介绍
- DRF(Django REST framework)是一个用于构建基于 Django 的 Web API 的强大框架。
- 在 DRF 中,序列化组件是其中一个核心组件,用于在 API 请求和响应中处理数据的转换和验证。
- 序列化组件的主要功能是将复杂的数据结构(例如模型对象)转换为可以序列化(序列化为 JSON、XML 等格式)和传输的数据,并且能够根据所需的数据结构对传入的数据进行反序列化,还原为程序可操作的对象。
【2】重要特点和用法:
-
定义序列化类:在 DRF 中,我们需要创建一个继承自
serializers.Serializer
或serializers.ModelSerializer
的序列化类。这个类定义了要序列化和反序列化的字段和规则。 -
字段类型:序列化类中的字段用于指定数据结构中的字段以及其对应的类型。DRF 提供了多种字段类型,如字符串字段 (
CharField
)、整数字段 (IntegerField
)、日期时间字段 (DateTimeField
) 等。 -
嵌套关系:序列化类支持嵌套关系的处理,可以通过使用
Serializer
字段或ModelSerializer
字段来表示两个模型之间的关联关系。 -
验证和转换:序列化组件提供了数据验证和转换的功能,可以在反序列化时验证输入数据的有效性,并对输入数据进行转换,使其符合定义的字段规则。
-
增加额外的字段和逻辑:在序列化类中,可以添加额外的字段和自定义方法,来处理复杂的业务逻辑,如计算属性和关联模型的反向查询等。
-
序列化输出:序列化组件将序列化类中定义的字段转换为指定的输出格式(JSON、XML 等),方便进行数据传输和展示。
-
反序列化输入:序列化组件能够将传入的数据反序列化为程序可操作的对象,以便进行进一步的处理和保存。
【3】小结
- 序列化
- 序列化器会把模型对象(queryset,单个对象)转换成字典
- 经过response以后变成json字符串
- 反序列化
- 把客户端发送过来的数据,经过request.data以后变成字典
- 序列化器可以把字典转成模型
- 反序列化
- 完成数据校验功能
【二】基本使用
【1】准备数据模型
from django.db import models
# Create your models here.
class Book(models.Model):
name = models.CharField(max_length=32)
price = models.IntegerField()
【2】写查询所有图书的接口
(APIView+序列化类)
(1)查询所有数据
- 路由
path('books/', BookView.as_view()),
- 视图
from django.shortcuts import render
# Create your views here
from rest_framework.views import APIView
from rest_framework.response import Response
from .serializers.my_serializer import BookSerializer
from app01 import models
class BookView(APIView):
def get(self, request):
book_list = models.Book.objects.all()
# 使用序列化类完成序列化
# instance : 实例(对象)
# data : 数据
# many=True : 如果是queryset对象,一般都是必须加
# many=False : 如果是 .first() 一般不写,默认不写是 False
book_ser = BookSerializer(instance=book_list, many=True)
data = book_ser.data # 将 book_ser 转成字典 -- 列表套字典
print(f"data的数据是{data}", f"data的类型是{type(data)}")
# data的数据是[OrderedDict([('id', 1), ('name', '西游记'), ('price', 999)])]
# data的类型是<class 'rest_framework.utils.serializer_helpers.ReturnList'>
return Response({"code": 1000, "msg": "查询成功", "data": data})
- 序列化器
# -*-coding: Utf-8 -*-
# @File : my_serializer .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/7/27
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
# 要序列化的字段
id = serializers.IntegerField()
name = serializers.CharField()
price = serializers.IntegerField()
- 后端返回给前端的数据
{
"code": 1000,
"msg": "查询成功",
"data": [
{
"id": 1,
"name": "西游记",
"price": 999
}
]
}
(2)查询单条数据
- 路由
path('books/<int:pk>/', BookDetailView.as_view()),
- 视图
class BookDetailView(APIView):
def post(self, request, pk):
book_list = models.Book.objects.filter(pk=pk).first()
# 使用序列化类完成序列化
# instance : 实例(对象)
# data : 数据
# many=True : 如果是queryset对象,一般都是必须加
# many=False : 如果是 .first() 一般不写,默认不写是 False
book_ser = BookSerializer(instance=book_list)
data = book_ser.data # 将 book_ser 转成字典 -- 列表套字典
return Response({"code": 1000, "msg": "查询成功", "data": data})
- 后端返回给前端的数据
{
"code": 1000,
"msg": "查询成功",
"data": {
"id": 1,
"name": "西游记",
"price": 999
}
}
【3】小结
(1)制作序列化器
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
# 要序列化的字段
id = serializers.IntegerField()
name = serializers.CharField()
price = serializers.IntegerField()
- 自定义类并继承
serializers.Serializer
- 序列化器中的字段可以选择性添加
- 使用哪个字段就将那个字段添加上去即可
- 序列化器内的字段尽量跟模型表中的字段类型相匹配
(2)使用序列化器
class BookView(APIView):
def get(self, request):
book_list = models.Book.objects.all()
# 使用序列化类完成序列化
# instance : 实例(对象)
# data : 数据
# many=True : 如果是queryset对象,一般都是必须加
# many=False : 如果是 .first() 一般不写,默认不写是 False
book_ser = BookSerializer(instance=book_list, many=True)
data = book_ser.data # 将 book_ser 转成字典 -- 列表套字典
print(f"data的数据是{data}", f"data的类型是{type(data)}")
# data的数据是[OrderedDict([('id', 1), ('name', '西游记'), ('price', 999)])]
# data的类型是<class 'rest_framework.utils.serializer_helpers.ReturnList'>
return Response({"code": 1000, "msg": "查询成功", "data": data})
-
参数
- instance : 实例(对象)
- data : 数据
- many=True : 如果是queryset对象,一般都是必须加
- many=False : 如果是 .first() 一般不写,默认不写是 False
-
序列化的结果
data = book_ser.data
- 将 book_ser 转成字典 -- 列表套字典
- data的类型是
<class 'rest_framework.utils.serializer_helpers.ReturnList'>
【三】常用序列化字段和参数
【1】常用字段
字段 | 字段构造方式 | 详解 |
---|---|---|
BooleanField | BooleanField() | 布尔字段用于存储和表示真/假值。构造方法不需要参数。 |
NullBooleanField | NullBooleanField() | 可空布尔字段是可以接受三个值的布尔字段:True、False和None(空值)。构造方法不需要参数。 |
CharField | CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True) | 字符字段用于存储短文本数据。max_length指定字符的最大长度,min_length指定最小长度。allow_blank指定是否允许为空值。trim_whitespace指定是否在保存数据前去除首尾的空格。 |
EmailField | EmailField(max_length=None, min_length=None, allow_blank=False) | Email字段用于存储和验证电子邮件地址。max_length指定最大字符长度,min_length指定最小长度。allow_blank指定是否允许为空值。 |
RegexField | RegexField(regex, max_length=None, min_length=None, allow_blank=False) | 正则表达式字段用于存储和验证符合特定模式的数据。regex指定正则表达式,max_length指定最大字符长度,min_length指定最小长度。allow_blank指定是否允许为空值。 |
SlugField | SlugField(max_length=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9_-]+ | Slug字段用于存储URL友好的文本标识符。max_length指定最大字符长度,min_length指定最小长度。allow_blank指定是否允许为空值。 |
URLField | URLField(max_length=200, min_length=None, allow_blank=False) | URL字段用于存储和验证URL地址。max_length指定最大字符长度,min_length指定最小长度。allow_blank指定是否允许为空值。 |
UUIDField | UUIDField(format='hex_verbose') format: 1) 'hex_verbose' 如"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex' 如 "5ce0e9a55ffa654bcee01238041fb31a" 3)'int' - 如: "1234567012312313134124512351145114" 4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a" |
UUID字段用于存储和验证通用唯一标识符。format参数指定UUID的格式。 |
IPAddressField | IPAddressField(protocol='both', unpack_ipv4=False, **options) | IP地址字段用于存储和验证IP地址。protocol参数指定所允许的IP地址协议类型,unpack_ipv4参数指定是否拆分IPv4地址。 |
IntegerField | IntegerField(max_value=None, min_value=None) | 整数字段用于存储整数值。max_value指定最大值,min_value指定最小值。 |
FloatField | FloatField(max_value=None, min_value=None) | 浮点数字段用于存储浮点数值。max_value指定最大值,min_value指定最小值。 |
DecimalField | DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置 | 十进制字段用于存储精确的十进制数值。max_digits指定最多位数,decimal_places指定小数点位置。coerce_to_string指定是否将值强制转化为字符串形式。max_value指定最大值,min_value指定最小值。 |
DateTimeField | DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None) | 日期时间字段用于存储日期和时间。format参数指定日期时间的输出格式,input_formats参数指定输入格式。 |
DateField | DateField(format=api_settings.DATE_FORMAT, input_formats=None) | 日期字段用于存储日期。format参数指定日期的输出格式,input_formats参数指定输入格式。 |
TimeField | TimeField(format=api_settings.TIME_FORMAT, input_formats=None) | 时间字段用于存储时间。format参数指定时间的输出格式,input_formats参数指定输入格式。 |
DurationField | DurationField() | 持续时间字段用于存储一段时间的持续时间。构造方法不需要参数。 |
ChoiceField | ChoiceField(choices) choices与Django的用法相同 | 选择字段用于存储和验证预定义选项中的一个值。choices参数指定可选的选项值。 |
MultipleChoiceField | MultipleChoiceField(choices) | 多选字段用于存储和验证多个预定义选项中的值。choices参数指定可选的选项值。 |
FileField | FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) | 文件字段用于上传和保存文件。max_length指定文件名的最大长度,allow_empty_file指定是否允许为空文件。use_url指定是否使用文件的URL路径。 |
ImageField | ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) | 图片字段用于上传和保存图片文件。max_length指定文件名的最大长度,allow_empty_file指定是否允许为空文件。use_url指定是否使用图片的URL路径。 |
ListField | ListField(child=, min_length=None, max_length=None) | 列表字段用于存储和验证列表类型的数据。child参数指定列表中元素的类型,min_length指定最小长度,max_length指定最大长度。 |
DictField | DictField(child=) | 字典字段用于存储和验证字典类型的数据。child参数指定字典中value的类型。 |
-
总结:常用字段
IntegerField CharField DateTimeField DecimalField ListField和DictField
【2】字段参数(校验数据)
(1)选项参数:(CharField,IntegerField)
参数名称 | 作用 |
---|---|
max_length | 最大长度 |
min_lenght | 最小长度 |
allow_blank | 是否允许为空 |
trim_whitespace | 是否截断空白字符 |
max_value | 最小值 |
min_value | 最大值 |
(2)通用参数:
参数名称 | 说明 |
---|---|
read_only | 表明该字段仅用于序列化输出,默认False |
write_only | 表明该字段仅用于反序列化输入,默认False |
required | 表明该字段在反序列化时必须输入,默认True |
default | 反序列化时使用的默认值 |
allow_null | 表明该字段是否允许传入None,默认False |
-
常用 参数
read_only write_only
【四】反序列化之校验(增加)
- 序列化类
class BookSerializer(serializers.Serializer):
# 要序列化的字段
# required : 是否必填字段,默认为True,必填字段
id = serializers.IntegerField(required=False)
# allow_blank:传入的数据允许为空,默认不为空
# max_length: 限制字符串的最大长度
name = serializers.CharField(allow_blank=True,max_length=8)
# max_value:限制最大值
# min_value:限制最小值
# error_messages:自定义错误信息
price = serializers.IntegerField(max_value=100, min_value=10, error_messages={"error": "价格必须在10-100之间"})
- 后端使用
# 新增
def post(self, request):
# 前端传入数据,通过request.data取到数据,将数据保存到数据库中
# 借助于序列化类,完成校验和反序列化
# data : 前端传入的数据
book_ser = BookSerializer(data=request.data)
# 校验数据
if book_ser.is_valid():
# 三层:字段自己的校验/全局钩子校验/局部钩子校验
# 校验通过,保存数据
# validated_data:校验通过的数据
# 新增字段限制条件 ---> 在序列化类中的字段中添加限制条件
after_data = book_ser.validated_data
else:
print(book_ser.errors) # 校验失败的错误
return Response({"code": 100, "msg": "成功"})
-
小结:反序列化有三层校验
-
字段自己的:写的字段参数:required/max_length ...
-
局部钩子:写在序列化类中的方法
- 方法名必须是 validate_字段名
def validate_name(self, name): if 'sb' in name: # 不合法,抛异常 raise ValidationError('书名中不能包含sb') else: return name
-
全局钩子:写在序列化类中的方法
- 方法名必须是 validate
def validate(self, attrs): price = attrs.get('price') name = attrs.get('name') if name == price: raise ValidationError('价格不能等于书名') else: return attrs
-
只有三层都通过,在视图类中:
- ser.is_valid(): 才是True,才能保存
-
【五】反序列化之保存(增加)
- 新增接口
- 数据校验后
- 调用序列化类的
.save()
方法 - 同时还要在序列化类中重写
create
方法
- 序列化类
class BookSerializer(serializers.Serializer):
# 要序列化的字段
# required : 是否必填字段,默认为True,必填字段
id = serializers.IntegerField(required=False)
# allow_blank:传入的数据允许为空,默认不为空
# max_length: 限制字符串的最大长度
name = serializers.CharField(allow_blank=True, max_length=8)
# max_value:限制最大值
# min_value:限制最小值
# error_messages:自定义错误信息
price = serializers.IntegerField(max_value=100, min_value=10, error_messages={"error": "价格必须在10-100之间"})
def create(self, validated_data):
# validated_data 校验过后的数据
# **validated_data : 解耦,将数据打散
book = models.Book.objects.create(**validated_data)
return book
- 后端使用
# 新增
def post(self, request):
# 前端传入数据,通过request.data取到数据,将数据保存到数据库中
# 借助于序列化类,完成校验和反序列化
# data : 前端传入的数据
book_ser = BookSerializer(data=request.data)
# 校验数据
if book_ser.is_valid():
# 三层:字段自己的校验/全局钩子校验/局部钩子校验
# 校验通过,保存数据
# validated_data:校验通过的数据
# 新增字段限制条件 ---> 在序列化类中的字段中添加限制条件
after_data = book_ser.validated_data
ser.save() # 会保存数据,但是会报错,因为不知道要保存到哪张表中
return Response({"code": 100, "msg": "成功"})
else:
print(book_ser.errors) # 校验失败的错误
return Response({"code": 100, "msg": "失败", "error": book_ser.errors})
- 小结
- 序列化类中重写 create 方法
- 在后端逻辑中调用 save 方法
- 如果调用create方法,校验通过的 validated_data 数据不会自动传入
- 需要传入的数据
ser = BookSerializer(data=request.data)
【六】反序列化之保存(修改)
【1.0】指定字段修改数据
- 序列化类
class BookSerializer(serializers.Serializer):
# 要序列化的字段
# required : 是否必填字段,默认为True,必填字段
id = serializers.IntegerField(required=False)
# allow_blank:传入的数据允许为空,默认不为空
# max_length: 限制字符串的最大长度
name = serializers.CharField(allow_blank=True, max_length=8)
# max_value:限制最大值
# min_value:限制最小值
# error_messages:自定义错误信息
price = serializers.IntegerField(max_value=100, min_value=10, error_messages={"error": "价格必须在10-100之间"})
def create(self, validated_data):
# validated_data 校验过后的数据
# **validated_data : 解耦,将数据打散
book = models.Book.objects.create(**validated_data)
return book
def update(self, instance, validated_data):
# instance : 需要修改的对象 --- book
# validated_data : 需要修改并且是校验过的数据
instance.name = validated_data.get('name')
instance.price = validated_data.get('price')
# 修改完要保存数据
instance.save()
- 后端使用
class BookDetailView(APIView):
def post(self, request, pk):
book_list = models.Book.objects.filter(pk=pk).first()
# 使用序列化类完成序列化
# instance : 实例(对象)
# data : 数据
# many=True : 如果是queryset对象,一般都是必须加
# many=False : 如果是 .first() 一般不写,默认不写是 False
book_ser = BookSerializer(instance=book_list)
data = book_ser.data # 将 book_ser 转成字典 -- 列表套字典
return Response({"code": 1000, "msg": "查询成功", "data": data})
# 新增
def put(self, request, pk):
book = Book.objects.get(pk=pk)
ser = BookSerializer(instance=book, data=request.data)
if ser.is_valid():
ser.save() # 也会报错,需要重写 update 方法
return Response({"code": 100, "msg": "修改成功"})
else:
return Response({"code": 100, "msg": "修改失败", "error": book_ser.errors})
- 问题就是
- 在重写 update 方法的时候,需要一个个的去取字段然后做修改
- 当字段太多的时候,会大大影响效率
【2.0】多字段优化
class BookSerializer(serializers.Serializer):
# 要序列化的字段
# required : 是否必填字段,默认为True,必填字段
id = serializers.IntegerField(required=False)
# allow_blank:传入的数据允许为空,默认不为空
# max_length: 限制字符串的最大长度
name = serializers.CharField(allow_blank=True, max_length=8)
# max_value:限制最大值
# min_value:限制最小值
# error_messages:自定义错误信息
price = serializers.IntegerField(max_value=100, min_value=10, error_messages={"error": "价格必须在10-100之间"})
def create(self, validated_data):
# validated_data 校验过后的数据
# **validated_data : 解耦,将数据打散
book = models.Book.objects.create(**validated_data)
return book
def update(self, instance, validated_data):
# instance : 需要修改的对象 --- book
# validated_data : 需要修改并且是校验过的数据
for item in validated_data: # validated_data: {"name":"dream","age":18}
# 利用反射语法
setattr(instance, item, validated_data[item])
# 等同于
# setattr(book, "name", "dream")
# setattr(book, "age", 18)
# 修改完要保存数据
instance.save()
- 小结
- 序列化类中重写 update 方法
- 在后端逻辑中调用 save 方法
- 需要传入的参数
ser = BookSerializer(instance=book,data=request.data)
【七】save方法简解
-
在视图类中,无论是保存还是修改,都是调用序列化类的 save() 方法
-
底层实现逻辑是根据 instance 判断需要做出的对应的方法
def save(self, **kwargs):
# 根据传入的 instance 对象,进行方式的判断 update/create
# 如果是 update 方法 需要传入需要需要修改的独享和修改的数据
if self.instance is not None:
self.instance = self.update(self.instance, validated_data)
assert self.instance is not None, (
'`update()` did not return an object instance.'
)
else:
# 如果是 create 需要传入修改的数据
self.instance = self.create(validated_data)
assert self.instance is not None, (
'`create()` did not return an object instance.'
)
return self.instance
-
如果是 update 方法 需要传入需要需要修改的独享和修改的数据
-
如果是 create 需要传入修改的数据
【作业】
Publish 的5个接口
-name
-addr
-phone
出版社名字不能包含东京,最大长度不能超过10,最短不能短于2
地址长度不能超过20,没有最短现在,地址不能以上海开头
手机号必须11位
出版社名字和地址名字不能一样
- 路由
path('publish/', PublishView.as_view()),
path('publish/<int:pk>/', PublishDetailView.as_view()),
path('publish/add/', PublishDetailView.as_view()),
- 视图
class PublishView(APIView):
# 查询所有信息
def get(self, request):
publish_obj = models.Publish.objects.all()
publish_ser = PublishSerializer(instance=publish_obj, many=True)
data = publish_ser.data
return Response({"code": 200, "msg": "查询成功", "data": data})
class PublishDetailView(APIView):
# 查询指定信息
def get(self, request, pk):
publish_obj = models.Publish.objects.filter(pk=pk).first()
if publish_obj:
publish_ser = PublishSerializer(instance=publish_obj)
data = publish_ser.data
return Response({"code": 200, "msg": "查询成功", "data": data})
else:
return Response({"code": 201, "msg": "查询失败,书籍不存在", "data": []})
# 新增
def post(self, request):
publish_ser = PublishSerializer(data=request.data)
if publish_ser.is_valid():
publish_ser.save()
after_data = publish_ser.validated_data
print(after_data)
return Response({"code": 200, "msg": "保存成功", "data": []})
else:
return Response({"code": 201, "msg": "保存失败", "error": publish_ser.errors})
- 序列化类
class PublishSerializer(serializers.Serializer):
id = serializers.IntegerField(required=False)
name = serializers.CharField(max_length=12, min_length=4)
addr = serializers.CharField(max_length=18, error_messages={"errors": "地址最大长度不能超过18"})
phone = serializers.IntegerField(error_messages={"errors": "手机号必须是11位"})
def create(self, validated_data):
publish = models.Publish.objects.create(**validated_data)
return publish
def update(self, instance, validated_data):
for item in validated_data:
setattr(instance, item, validated_data[item])
instance.save()
return instance
def validate_name(self, name):
# 出版社名字不能包含东京
if "东京" in name:
raise ValidationError("地址中不能包含敏感字 '东京' !")
else:
return name
def validate_addr(self, addr):
# 地址不能以上海开头
if addr.startswith("上海"):
raise ValidationError("地址中不能以上海开头 !")
else:
return addr
def validate_phone(self, phone):
if len(str(phone)) != 11:
raise ValidationError("电话必须是11位")
else:
return phone
def validate(self, attrs):
# 出版社名字和地址名字不能一样
name = attrs.get('name')
addr = attrs.get('addr')
if name == addr:
raise ValueError("姓名和地址不能相等!")
else:
return attrs
- 模型表
class Publish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=255)
phone = models.IntegerField()
【补充】
from django.db.models import QuerySet
from rest_framework.response import Response
from rest_framework.views import APIView
from .models import User, Book, Publish
from .serializers import UserSerializer, BookSerializer, PublishSerializer
from rest_framework.generics import GenericAPIView
###################################方式一:基于APIView封装方法#####################################
# 构建自定义返回对象
def CommonResponse(code=100, msg="请求成功", status=None, **kwargs):
# 构建返回格式字典:默认是 {'code': 100, 'msg': "请求成功"}
data = {'code': code, 'msg': msg}
# 如果有数据传进来进行数据的更新
if kwargs:
for name, value in kwargs.items():
data[name] = value
# 完整的数据格式示例 : {'code': 100, 'msg': "请求成功", 'data': {....}}
return Response(data=data, status=status)
# 构建 视图基类
class GenericView(APIView):
# 定义序列化类校验方法
def _check_serializers(self, serializer_class, instance=None, many=False, data=None, **kwargs):
# 没有数据 data -----> 序列化返回数据
if not data:
if many:
# many=True -----> 序列化返回多条数据
return serializer_class(instance=instance, many=many, **kwargs)
else:
# many=False -----> 序列化返回单条数据
return serializer_class(instance=instance, **kwargs)
# 有数据 data -----> 反序列化保存数据
return serializer_class(instance=instance, data=data, **kwargs)
# 定义中转调用序列化器
def get_serializer_class(self, serializer_class=None, instance=None, many=False, data=None, **kwargs):
# serializer_class : 视图需要用到的序列化类
# instance : 视图传过来的 对象 (.all()/.first())
# many : 是否序列化多条
# data : 反序列化的数据
return self._check_serializers(serializer_class=serializer_class, instance=instance, many=many,
data=data, **kwargs)
# 定义校验视图函数 ---> 返回指定的表模型和序列化器
def _check_view(self, request):
# 根据 request 对象获取当前视图类
view_name = request.resolver_match.view_name
view_name = view_name.split('.')[-1]
# 如果属于指定视图类则返回指定 模型表和序列化类
if view_name.split('.')[-1] in ['UserView', 'UserDetailView']:
model_name = User
serializer_class = UserSerializer
elif view_name.split('.')[-1] in ['BookView', 'BookDetailView']:
model_name = Book
serializer_class = BookSerializer
else:
model_name = Publish
serializer_class = PublishSerializer
# 将 模型表和序列化类 返回
return model_name, serializer_class
# 定义 获取 queryset 的方法
def get_queryset(self, model_name, pk=None):
# 带 PK 返回 指定对象
if pk:
return model_name.objects.filter(pk=pk).first()
# 不带 PK 返回 全部对象
return model_name.objects.all()
# 定义基类 get 方法 --- 查询
def _get(self, request, pk=None, *args, **kwargs):
# 判断是查询单条还是全部
if pk:
# 获取 模型表和序列化类
model_name, serializer_class = self._check_view(request)
# 获取 queryset 对象 ---> 指定
queryset = self.get_queryset(model_name, pk)
# 调用序列化类序列化数据
serializer = self.get_serializer_class(serializer_class=serializer_class, instance=queryset)
# 返回自定义 数据
return CommonResponse(data=serializer.data)
else:
# 获取 模型表和序列化类
model_name, serializer_class = self._check_view(request)
# 获取 queryset 对象 ---> 全部
queryset = self.get_queryset(model_name)
# 调用序列化类序列化数据
serializer = self.get_serializer_class(serializer_class=serializer_class, instance=queryset,
many=True)
# 返回自定义 数据
return CommonResponse(data=serializer.data)
def _post(self, request, *args, **kwargs):
model_name, serializer_class = self._check_view(request)
serializer = self.get_serializer_class(serializer_class=serializer_class, data=request.data)
if serializer.is_valid():
serializer.save()
return CommonResponse(msg="创建成功")
else:
return CommonResponse(error=serializer.errors)
# 定义基类 put 方法 --- 更新
def _put(self, request, pk, *args, **kwargs):
# 获取 模型表和序列化类
model_name, serializer_class = self._check_view(request)
# 获取 queryset 对象 ---> 指定
queryset = self.get_queryset(model_name, pk)
# 调用序列化类序列化数据
serializer = self.get_serializer_class(serializer_class=serializer_class, instance=queryset,
data=request.data)
# 调用序列化类校验数据
if serializer.is_valid():
# 保存数据 ---- 触发 update 方法
serializer.save()
# 返回自定义 数据
return CommonResponse(msg="数据更新成功")
else:
# 返回自定义 数据 --- 错误
return CommonResponse(error=serializer.errors)
def _delete(self, request, pk, *args, **kwargs):
# 获取 模型表和序列化类
model_name, serializer_class = self._check_view(request)
# 获取 queryset 对象 ---> 指定
queryset = self.get_queryset(model_name, pk)
# 直接删除对象
queryset.delete()
# 返回自定义 数据
return CommonResponse(msg="删除数据成功")
class UserView(GenericView):
# 获取全部信息
def get(self, request, *args, **kwargs):
return self._get(request, *args, **kwargs)
# 创建信息
def post(self, request, *args, **kwargs):
return self._post(request, *args, **kwargs)
class UserDetailView(GenericView):
# 获取单条信息
def get(self, request, pk, *args, **kwargs):
return self._get(request, pk, *args, **kwargs)
# 更新信息
def put(self, request, pk, *args, **kwargs):
return self._put(request, pk, *args, **kwargs)
# 删除信息
def delete(self, request, pk, *args, **kwargs):
return self._delete(request, pk, *args, **kwargs)
class BookView(GenericView):
# 获取全部信息
def get(self, request, *args, **kwargs):
return self._get(request, *args, **kwargs)
# 创建信息
def post(self, request, *args, **kwargs):
return self._post(request, *args, **kwargs)
class BookDetailView(GenericView):
# 获取单条信息
def get(self, request, pk, *args, **kwargs):
return self._get(request, pk, *args, **kwargs)
# 更新信息
def put(self, request, pk, *args, **kwargs):
return self._put(request, pk, *args, **kwargs)
# 删除信息
def delete(self, request, pk, *args, **kwargs):
return self._delete(request, pk, *args, **kwargs)
class PublishView(GenericView):
# 获取全部信息
def get(self, request, *args, **kwargs):
return self._get(request, *args, **kwargs)
# 创建信息
def post(self, request, *args, **kwargs):
return self._post(request, *args, **kwargs)
class PublishDetailView(GenericView):
# 获取单条信息
def get(self, request, pk, *args, **kwargs):
return self._get(request, pk, *args, **kwargs)
# 更新信息
def put(self, request, pk, *args, **kwargs):
return self._put(request, pk, *args, **kwargs)
# 删除信息
def delete(self, request, pk, *args, **kwargs):
return self._delete(request, pk, *args, **kwargs)
##############################方法二:基于GenericAPIView封装方法##################################
'''
from rest_framework import generics
from rest_framework.response import Response
from .models import User, Book, Publish
from .serializers import UserSerializer, BookSerializer, PublishSerializer
# 构建自定义返回对象
def CommonResponse(code=100, msg="请求成功", status=None, **kwargs):
data = {'code': code, 'msg': msg}
if kwargs:
for name, value in kwargs.items():
data[name] = value
return Response(data=data, status=status)
# 构建基础视图类
class BaseView(generics.GenericAPIView):
queryset = None
serializer_class = None
def get_queryset(self):
return self.queryset.all()
def get_serializer(self, *args, **kwargs):
return self.serializer_class(*args, **kwargs)
def get_object(self, pk):
return generics.get_object_or_404(self.get_queryset(), pk=pk)
def get(self, request, pk=None):
if pk:
instance = self.get_object(pk)
serializer = self.get_serializer(instance)
else:
queryset = self.get_queryset()
serializer = self.get_serializer(queryset, many=True)
return CommonResponse(data=serializer.data)
def post(self, request):
serializer = self.get_serializer(data=request.data)
if serializer.is_valid():
serializer.save()
return CommonResponse(msg="创建成功")
else:
return CommonResponse(error=serializer.errors)
def put(self, request, pk):
instance = self.get_object(pk)
serializer = self.get_serializer(instance, data=request.data)
if serializer.is_valid():
serializer.save()
return CommonResponse(msg="数据更新成功")
else:
return CommonResponse(error=serializer.errors)
def delete(self, request, pk):
instance = self.get_object(pk)
instance.delete()
return CommonResponse(msg="删除数据成功")
# 用户视图类
class UserView(BaseView):
queryset = User.objects.all()
serializer_class = UserSerializer
class UserDetailView(BaseView):
queryset = User.objects.all()
serializer_class = UserSerializer
# 图书视图类
class BookView(BaseView):
queryset = Book.objects.all()
serializer_class = BookSerializer
class BookDetailView(BaseView):
queryset = Book.objects.all()
serializer_class = BookSerializer
# 出版社视图类
class PublishView(BaseView):
queryset = Publish.objects.all()
serializer_class = PublishSerializer
class PublishDetailView(BaseView):
queryset = Publish.objects.all()
serializer_class = PublishSerializer
'''
【补充】IntegerField 和 BigIntegerField 的区别:
IntegerField和BigIntegerField是Django框架中用于存储整数值的两种字段类型,它们之间有以下区别:
-
存储范围:
- IntegerField:存储范围是一个32位有符号整数,即介于-2,147,483,648到+2,147,483,647之间的整数。
- BigIntegerField:存储范围是一个64位有符号整数,即介于-9,223,372,036,854,775,808到+9,223,372,036,854,775,807之间的整数。
-
存储空间:
- IntegerField:使用4字节内存来存储整数值。
- BigIntegerField:使用8字节内存来存储整数值。
-
应用场景:
- IntegerField:适用于较小的整数值,如用户ID、年龄等。
- BigIntegerField:适用于较大的整数值,如订单号、数据库记录ID等。
需要注意的是,在大多数情况下,IntegerField已经足够满足应用需求。只有当需要存储非常大的整数值时,才需要使用BigIntegerField。
本文来自博客园,作者:Chimengmeng,转载请注明原文链接:https://www.cnblogs.com/dream-ze/p/17593138.html