drf安装、序列化组件
一、drf的安装使用
1、drf介绍
drf全称djangorestframework,是django的一个第三方app,目的是方便我们快速实现符合restful规范的接口
2、安装使用
2.1 安装模块
djangorestframework
2.2 django 是2版本,用不了drf最新(适当降版本),会自动卸载django,装最django新版4.x
使用 djagno 3.1.12 可以使用最新版本drf
2.3 注册app(arf是第三方app)
INSTALLED_APPS = [
'rest_framework',
]
2.4 写路由
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('books', BookView, 'books')
urlpatterns += router.urls
2.5 写视图类
from rest_framework.viewsets import ModelViewSet
from .serializer import BookSerializer
class BookView(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
2.6 写序列化类
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"
二、序列化组件(重要!!)
1、序列化组件介绍
DRF的序列化组件是该框架的核心部分,用于在Django应用程序中处理复杂数据结构的序列化和反序列化。
它的主要作用是在 models 和 views 视图函数之间建立桥梁,使数据能够在数据库模型和API接口之间进行转换,同时还能够进行数据验证、字段选择和数据转换。
序列化组件有以下作用:
-
序列化(Serialization): 序列化是将数据从复杂的数据结构(如Django模型)转换为可以在API响应中传输的格式(如JSON)。通过使用序列化器,你可以定义模型的字段,并指定哪些字段需要包含在API响应中。这样,当你从数据库中检索数据并将其传递到API响应中时,序列化器会自动将数据转换为适当的格式。
-
反序列化(Deserialization): 反序列化是将API请求中的数据转换为数据库模型或其他Python对象。例如,当用户通过API提交数据以创建或更新资源时,DRF的序列化器可以将传入的数据验证并将其转换为数据库模型实例,然后保存到数据库中。
-
数据验证和转换: 序列化组件允许你定义字段的验证规则,例如字段是否必需、数据类型是否正确以及其他自定义验证。它还允许你在保存数据之前对数据进行自定义转换,以便确保数据的一致性和准确性。
-
嵌套关系处理: 在复杂的数据模型中,可能存在多层嵌套的关系。序列化器允许你在API响应中嵌套关联的数据,并在API请求中处理这些嵌套的关系。
-
字段选择和映射: 有时候你可能只需要返回模型的部分字段,而不是全部字段。序列化器允许你选择要包含在API响应中的字段,从而减少传输的数据量。此外,它还支持字段的重命名,使API的字段名与模型的字段名可以不同。
总之,DRF的序列化组件使得在Django项目中处理复杂数据结构、数据验证和数据转换变得更加简单和灵活。通过定义序列化器,你可以更好地控制数据的输入和输出,同时提供一种清晰的方式来处理API请求和响应中的数据。
2、序列化组件的引入
2.1 新建一个py文件---> serializer.py ---> 写一个序列化类
继承drf提供的serializers.Serializer
在类中写要序列化的字段:字段类---> 跟之前学过的models.py中的字段类完全对应,但是比models多
# 写序列化类
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from .models import User, Book
class UserSerializer(serializers.Serializer):
# 写要序列化的字段
# 字段限制
name = serializers.CharField(max_length=8, min_length=3, required=True)
hobby = serializers.CharField()
password = serializers.CharField()
age = serializers.IntegerField()
# 局部钩子
# 写一个方法 validate_字段名,传入要校验的数据--》前端传入的
def validate_name(self, value):
if value.startswith('sb'):
raise ValidationError('不能以sb开头') # 如果校验失败,抛ValidationError
return value # 如果校验通过,返回 value,后续继续用
# 全局钩子
# 名字和hobby不能一致 多个字段的同时校验
def validate(self, attrs): # 前端传入的所有数据,局部校验通过之后attrs 字典
name = attrs.get('name')
hobby = attrs.get('hobby')
if name == hobby:
raise ValidationError('名字和爱好不能一样')
else:
return attrs
# 重写create方法
def create(self, validated_data): # validated_data:前端传入,校验过后的数据
user = User.objects.create(**validated_data)
return user
2.2 在视图类中,使用序列化类
多条:serializer=UserSerializer(instance=users,many=True)
# instance 要序列化的对象实例 (qs,单个对象) many=True表示序列化多条,如果不写就是序列化一条
单条:serializer=UserSerializer(instance=user)
2.3 拿到序列化后的数据
serializer.data 可能是列表,可能是字典
2.4 使用drf提供的Resposne 返回
from rest_framework.response import Response
三、
1、 路由
from django.contrib import admin
from django.urls import path
from app01.views import BookView,BookDetailView
urlpatterns = [
path('books/', BookView.as_view()),
path('books/<int:pk>', BookDetailView.as_view()),
]
2、 视图类
class BookView(APIView):
# 查看所有的数据
def get(self, request):
books = Book.objects.all()
ser = BookSerializer(instance=books, many=True)
return Response({'code': 100, '书名查询成功': ser.data}) # ser.data[1].get('name') 取一条记录的书名
# 添加一本书
def post(self, request, *args, **kwargs):
ser = BookSerializer(data=request.data) # 获取前端传来的数据(这里是APIView,可以在request.body中获取 )
if ser.is_valid():
ser.save() # 调用了序列化类的save:内部会触发序列化类中,数据库中实例没有数据执行create方法,否则执行update方法 ,不是models中的book.save(),这里是序列化提供的save
return Response({'code': 200, 'msg': '添加成功'})
else:
return Response({'code': 400, 'msg': ser.errors})
class BookDetailView(APIView):
# 修改数据一本书
def put(self, request, pk):
# 要用查出来的对象,使用传入的数据,做修改
book = Book.objects.filter(pk=pk).first()
ser = BookSerializer(instance=book, data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 200, 'msg': '修改成功'})
else:
return Response({'code': 400, 'msg': ser.errors})
# 删除一本书
def delete(self, request, pk):
Book.objects.filter(pk=pk).delete()
return Response({'code': 200, 'msg': '删除成功'})
# 获取一本书
def get(self, request, pk):
books = Book.objects.filter(pk=pk).first()
ser = BookSerializer(instance=books, many=False)
return Response({'code': 200, 'msg': '查询单条成功', '书名': ser.data.get('name')})
3、 序列化类 serializer.py
class BookSerializer(serializers.Serializer):
# 写要序列化的字段
# 字段自己
name = serializers.CharField(max_length=8, min_length=3, required=True)
price = serializers.IntegerField(max_value=200, min_value=50)
# 局部钩子
# 写一个方法 validate_字段名,传入要校验的数据--》前端传入的
def validate_name(self, value):
if value.startswith('sb'):
raise ValidationError('不能以sb开头') # 如果校验失败,抛ValidationError
return value # 如果校验通过,返回 value,后续继续用
# 重写create方法(添加时候使用)
def create(self, validated_data): # validated_data:前端传入,校验过后的数据
return Book.objects.create(**validated_data)
# 重写update方法(添加时候使用)
def update(self, instance, validated_data):
# instance是待修改的对象(books或者pk)validated_data是验证过的数据 本质还是request.data经过了数据校验
# 方式一
# instance.name = validated_data.get('name')
# instance.price = validated_data.get('price')
# instance.save()
# return instance
# 方式二 反射是通过字符串动态的获取或设置属性或方法
# get=getattr(self,'get')
# get()
for k in validated_data: # {"name":"西游记","price":99,"publish":南京出版社}
setattr(instance, k, validated_data.get(k)) # books, key, value
instance.save()
return instance
def delete(self, instance):
return Book.objects.filter(pk=instance).delete()
总结:
1 序列化校验:
ser.is_valid() 就会走校验
2 反序列化保存
-新增数据:(写,反序列化)
ser = BookSerializer(data=request.data) ser.save()--->触发 序列化类中的 create---》为什么?内部做了判断:根据是否有instance create中,自己写保存到哪个表中:有数据--》保存到某个表中
-修改数据:(写,反序列化)
ser = BookSerializer(instance=待修改对象,data=request.data) ser.save()--->触发 序列化类中的 update---》为什么?内部做了判断:根据是否有instance update中,有待修改对象,有数据---》修改完保存即可--》两种方式
四、序列化类 serializer.py
1、 常用字段类
# 写序列化类的时候,写了CharField,IntegerField 跟django中models中的类似
BooleanField、CharField、
IntegerField、DecimalField、
DateField、FileField
# 序列化类中的和models中的一一对应,但是序列化类中多一些
# 多的--->暂时有个印象,后面会详细讲
ListField
DictField
# 使用场景
{name:金鹏没,price:99,publish:{name:xx出版社,addr:南京},authors:[{},{}]}
2、
# 字段类上,可以传参数,是做反序列化校验用的(前端拿到的数据做反序列化) CharField:max_length,min_lenght,allow_blank: 可以不传
IntegerField:max_value,min_value
# 所有字段都可以用通用的
-非常重要:read_only,write_only
-default,required,allow_null

3、字段类的属性
# 如下写法,就能修改序列化的字段
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": "南京出版社"
},
五、
# 方案一:使用SerializerMethodField 定制
在序列化类中使用SerializerMethodField
publish_detail = serializers.SerializerMethodField()
def get_publish_detail(self, obj): # 返回什么,序列化后publish就是什么
# obj 就是序列化到的book对象
return {'name': self.publish.name, 'addr': self.publish.addr}
# 方案二: 在表模型中定制
-1 Book表模型中写方法,包装成数据属性
@property
def publish_dict(self):
return {'name': self.publish.name}
-2 序列化类中
publish_dict=serializers.DictField()
2、效果

# 反序列化之校验: ser.is_valid()
1 字段自己的校验规则(字段类的属性上)
2 局部钩子(给某个字段加校验规则)
3 全局钩子
# 反序列化保存
ser.save()---》必须序列化类中重写 create--》自己定保存到哪个表
def create(self, validated_data): # validated_data:前端传入,校验过后的数据
user = User.objects.create(**validated_data)
return user