表
class Book(models.Model):
name = models.CharField(max_length=32)
price = models.IntegerField()
publish = models.CharField(max_length=32)
路由
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', BookView.as_view()),
path('books//' , BookDetailView.as_view()),
]
序列化类
from rest_framework import serializers
from .models import Book
class BookSerializer(serializers.Serializer):
name = serializers.CharField()
price = serializers.IntegerField()
publish = serializers.CharField()
# 重写 create() 方法
# validated_data 是前端传入校验之后的数据
def create(self, validated_data):
# 注意:在这里要注意在前端传入的 key 必须与数据库的字段保持一致,否则是添加不成功的
book = Book.objects.create(**validated_data)
return book
# 重写update()
def update(self, instance, validated_data):
# instance 是待修改的对象
# validated_data 是校验过后的数据,是个字典
# 方式1:
# instance.name = validated_data.get('name')
# instance.price = validated_data.get('price')
# instance.publish = validated_data.get('publish')
# instance.save()
# return instance
# 方式2:推荐使用
# 方式2: 反射是通过字符串动态的获取或设置属性或方法
for key in validated_data: # {"name":"西游记", "price":99, "publish":"老男孩出版社"}
# 把k,v放入instance对象中,通过反射修改
setattr(instance, key, validated_data.get(key))
# 类似于 instance.name = validated_data.get('name') 这种修改数据
# 放入instance中后,记得保存
instance.save()
return instance
视图函数
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Book
from .serializer import BookSerializer
class BookView(APIView):
# 查询所有接口
def get(self, request, *args, **kwargs):
books = Book.objects.all()
ser = BookSerializer(instance=books, many=True)
return Response({'code': 100, 'msg': '查询成功', 'data': ser.data})
# 新增一条
def post(self, request, *args, **kwargs):
ser = BookSerializer(data=request.data)
if ser.is_valid():
ser.save() # 要在序列化类中重写create(),否则会报错
return Response({'code': 100, 'msg': '添加成功', 'data': ser.data})
else:
return Response({'code': 101, 'msg': ser.errors})
class BookDetailView(APIView):
# 查询一条
def get(self, request, pk, *args, **kwargs):
book = Book.objects.all().filter(pk=pk).first()
ser = BookSerializer(instance=book)
return Response({'code': 100, 'msg': f'id为{pk}的数据查询成功', 'data': ser.data})
def put(self, request, pk, *args, **kwargs):
# 方式1:推荐使用
# # 要用查询出来的数据,使用传入的数据,做修改
book = Book.objects.filter(pk=pk).first()
# 使用前端传入的数据,修改book
ser = BookSerializer(instance=book, data=request.data)
if ser.is_valid():
# 要在序列化类中重写update(),否则会报错
# 这是调用序列化类的 save() 才会触发 update() 方法的执行,不是 book.save()
ser.save()
return Response({'code': 100, 'msg': '数据修改成功', 'data': ser.data})
else:
return Response({'code': 101, 'msg': ser.errors})
# 方式2:
# from rest_framework import status
#
# book = Book.objects.filter(pk=pk).first()
# if not book:
# return Response({'code': 101, 'msg': '书籍不存在'}, status=status.HTTP_404_NOT_FOUND)
#
# field_to_update = request.data.get('field_to_update') # 获取要更新的字段名
# new_value = request.data.get('new_value') # 获取新值
#
# ser = BookSerializer(instance=book)
#
# if field_to_update:
# if field_to_update not in ser.fields:
# return Response({'code': 101, 'msg': '要更新的字段不存在'}, status=status.HTTP_400_BAD_REQUEST)
# setattr(book, field_to_update, new_value)
# else:
# ser = BookSerializer(instance=book, data=request.data)
# if not ser.is_valid():
# return Response({'code': 101, 'msg': ser.errors}, status=status.HTTP_400_BAD_REQUEST)
# ser.save()
#
# return Response({'code': 100, 'msg': '数据修改成功', 'data': BookSerializer(instance=book).data})
def delete(self, request, pk, *args, **kwargs):
Book.objects.filter(pk=pk).delete()
return Response({'code': 100, 'msg': '删除成功'})
# 1 序列化类---》做序列化
-多条一定要写 many = True
# 2 序列化校验:
ser.is_valid() 就会走校验
# 4 反序列化保存
-新增:
ser = BookSerializer(data=request.data)
ser.save()--->触发 序列化类中的 create---》为什么?内部做了判断:根据是否有instance
create中,自己写保存到哪个表中:有数据--》保存到某个表中
-修改
ser = BookSerializer(instance=待修改对象,data=request.data)
ser.save()--->触发 序列化类中的 update---》为什么?内部做了判断:根据是否有instance
update中,有待修改对象,有数据---》修改完保存即可--》两种方式
# 字段类的属性
# 如下写法,就能修改序列化的字段
class BookSerializer(serializers.Serializer):
# 用法一:最简单,拿表中的字段
xxx = serializers.CharField(source='name')
# 用法二 :跨表查询
publish = serializers.CharField(source='publish.name') # 自动对应成出版社的名字 可以通过 . 跨表查询
#用法三:表模型中写方法,拿到方法的返回值
yyy = serializers.CharField(source='get_name')
### models.py中
@property
def get_name(self):
return self.name+'sb'
# 前端看到:
{
"xxx": "西游记",
"price": 199,
"publish": "南京出版社"
},
-定制返回的字段格式,publish也是一个对象
{
"name": "信息",
"price": 12,
"publish": {name:xx,addr:xx}
}
-高级用法定制字段三种方案,目前暂用两种
-方案一:使用SerializerMethodField 定制
在序列化类中使用SerializerMethodField
publish_detail = serializers.SerializerMethodField()
def get_publish_detail(self, obj): # 返回什么,序列化后publish就是什么
# obj 就是序列化到的book对象
return {'name':obj.publish.name,'addr':obj.publish.addr}
-方案二: 在表模型中定制
-1 表模型中写方法,包装成数据属性
@property
def publish_dict(self):
return {'name': self.publish.name}
-2 序列化类中
publish_dict=serializers.DictField()
# 以后一个序列化类,想即做序列化,又做反序列化,会出现问题:字段不匹配,尤其是多表关联的字段
# 有的字段 既做序列化,又做反序列化
name = serializers.CharField()
price = serializers.IntegerField()
# 有的字段:只做序列化(read_only表示 只做序列化)
publish_dict = serializers.DictField(read_only=True) # 只做序列化
author_list = serializers.ListField(read_only=True) # 只做序列化
# 有的字段只做反序列化(write_only=True)-->是什么类型,取决于前端传入的格式什么样
publish_id = serializers.IntegerField(write_only=True) # 反序列化
authors = serializers.ListField(write_only=True) # 反序列化
# 保存方法需要自己重写
def create(self, validated_data): # {"name":"一条龙","price":999,"publish":1,"authors":[1,2]}
authors=validated_data.pop('authors')
book = Book.objects.create(**validated_data)
# 增加中间表的记录:图书和作者的关系
book.authors.add(*authors) # 向中间表中存入:这个图书关联的做作者
return book
# 笨办法:
序列化用一个序列化类
反序列化换另一个序列化类
-什么情况用反序列化校验?
做反序列化的时候,才用----》校验前端传入的数据
-1.API数据处理:当编写API视图函数,接收前端传递的JSON数据时
-2.表单数据处理:当处理用户提交的表单数据时
-3.数据创建和更新:在创建或更新数据库记录时
-4.输入验证:反序列化校验用于验证输入数据的类型、格式和规则
-5.数据转换:当需要将前端传入的数据转换为内部数据类型(例如日期字符串到日期对象)时
-6.业务逻辑验证:在处理特定的业务逻辑时
-三层校验:
字段自己:字段类属性---》可控制的比较小
局部钩子:单个字段校验
全局钩子:多个字段同时校验