DRF序列化组件

目录

-DRF

--定义

--安装

--基本使用

--drf中的request

-序列化组件

--基本介绍

--基本使用

---①Serializer

---②ModelSerializer

---序列化组件常用参数

---序列化组件修改数据

---序列化组件删除数据

---序列化组件新增数据

---source使用

 --- SerializerMethodField使用

 --- 局部钩子和全局钩子

--进阶使用

--- 基于GenericAPIView类写views.py中的五个接口函数

--- 基于GenericAPIView类和五个扩展类写views.py中的五个接口函数

--- 基于GenericAPIView类的9个子类写views.py中的五个接口函数

--- 基于ModelViewSet类写views.py中的五个接口函数

--- 自动生成路由

--- action装饰器使用

总结


-DRF

--定义

DRF(Django REST Framework)是一个建立在Django基础之上的Web应用开发框架,可以快速的开发REST API接口应用

在REST Framework中,提供了序列化器Serializer的定义,可以帮助我们简化序列化和反序列化的过程

不仅如此,还提供丰富的类视图、扩展类、视图集来简化视图的编写工作。

同时,REST Framework还提供了认证、权限、限流、过滤、分页、接口文档等功能支持;

还提供了一个API的Web可视化界面来方便查看测试接口

核心功能:缩减编写api接口的代码

--安装

pip install djangorestframework

--基本使用

drf使用的都是CBV的方式

1、在settings.py中注册
INSTALLEN_APPS = [
    'rest_framework',    # 固定注册方式
]
2、在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=16)
 执行数据库迁移命令
3、基于CBV方式写视图函数
from rest_framework.views import APIView
class BookApiView(APIView):
	def get(self, request,*args,**kwargs): #可接收多参数,下同
	    return HttpResponse('get请求')
	def post(self, request):
	    # print(request.data) # 当post请求过来时,不管什么格式的数据(json,urlencoded)都可在request.data中接收
	    return HttpResponse('post请求')
    …
4、注册路由
path('/books', views.BookApiView.as_view()), # 要加括号!

然后在postman上就可以通过http://127.0.0.1:8000/books/通过请求方式的不同调用不同的视图函数

--drf中的request

- request.data
"""
    新的request有一个新的属性:data
     - data是post请求携带的数据,返回结果为字典的形式
     - 在django中我们知道不同的编码格式存储在不同的方法中,如request.POST获取urlencoded编码格式的数据;request.body获取json格式的数据
     - 而在drf中,无论什么编码格式,只要是post提交的数据,都在request.data中
    所以以后取post提交的数据不要从request.POST中去了,要从request.data中取
"""
- request.query_params      # 就是request._request.GET
"""取get请求的数据不要从request.GET中取了,而是从request.query_params中取"""
- request.FIELS     
'''上传的文件'''

-序列化组件

--基本介绍

DRF自带一个序列化组件Serializer(类)

作用:

        1.序列化:Serializer会把模型对象(表对象,QuerySet对象)转换成字典,经过response后变为json字符串

        2.反序列化:把客户端发来的数据经过request后变为字典(request.data),Serializer可以把字典转为模型对象

        3.完成数据校验功能

--基本使用

---①Serializer

1、新建一个.py序列化组件文件(见名知意),在该文件下写序列化类,继承Serializer
    from rest_framework import serializers
    class BookSerializers(serializers.Serializer):
        ...
2、在类中写要序列化的字段
    # 写要序列化的字段
    id = serializers.CharField()
    name = serializers.CharField(max_length=16,min_length=4)
    # book_name = serializers.CharField(max_length=16,min_length=4, source='get_book_name')
    price = serializers.CharField()
    author = serializers.CharField()
3、写路径(这以查单个为例,发get请求,带主键为筛选条件)
    re_path('books/(?P<pk>\d+)/', views.BookApiView.as_view())
4、在视图类中使用
    from app01.mySerializer1 import BookSerializers
	from rest_framework.response import Response
	class BookApiView(APIView):
	    def get(self, request, pk):
	        # 序列化 先获得待查询pk的queryset对象
	        book_obj = models.Book.objects.filter(pk=pk).first()
	        # BookSerializers实例化生成序列化对象
	        book_serializers_obj = BookSerializers(book_obj)
	        # 固定返回格式 book_serializers_obj.data是一个字典
	        return Response(book_serializers_obj.data)
		"""
		Response是drf提供的响应对象,如果不用Response,就用JsonResponse,不过就没有drf提供的那么多功能了(比如浏览器查返回好看界面)
        """

---②ModelSerializer

'''序列化类也可以不继承Serializer,而是继承ModelSerializer(模型序列化组件),在Meta中对应模型表及规定序列化字段'''
from rest_framework.serializers import ModelSerializer
from app01.models import Book

class BookModelSerializer(ModelSerializer): # 类名任取
	class Meta:
	    model = Book         # 对应models.py中的模型表
	    fields = '__all__'   # 序列化所有字段
		# fields = ('name', 'price')    # 序列化指定字段 列表or元组
		# exclude = ('name', )          # 除外均序列化 列表or元组
		# read_only_fields = ['id']     # 设置只读字段
		'''extra_kwargs = [             # 设置其它
		    'price' : {'write_only' : True},
		]'''
        # depth = 1    # 深度:深一层(外键深入的意思,=1表示把关联了一层的外键字段也显示出来) 非常耗费效率,不能控制深入后想要查询的字段,不建议使用,写多层不会报错,有几层就深入几层

视图函数中使用方法一样,只是不需要重写create和update方法了。其余使用相同

---序列化组件常用参数

----常用字段类型

 ----常用选项参数

 ----通用参数

read_only    默认false,表明该字段仅读仅用于序列化输出。为true时postman中可以看到该字段,修改时不需要传该字段
write_only   默认false,表明该字段仅用于反序列化输出。为true时postman看不到该字段,修改时该字段需要传

required          表明该字段在反序列化时必须输入,默认true
default           反序列化时使用的默认值
allow_null        默认false,是否允许传入None
validators        使用的验证器
error_messages    包含错误代码和错误信息的字典

---序列化组件修改数据

当发送PUT请求时,修改数据

def put(self, request, pk):
    back_dict = {'code':1000, 'msg':'成功'}
    book_obj = models.Book.objects.filter(pk=pk).first()
	# 实例化生成对象时传入修改数据
    # book_serializers_obj = BookSerializers(book_obj, request.data)
	book_serializers_obj = BookSerializers(instance=book_obj, data=request.data)
    # 修改数据 验证修改后的数据是否合适 合适才能修改
    if book_serializers_obj.is_valid():
        # 保存数据
        book_serializers_obj.save() # 会报错 需重写updata()方法
        back_dict['datas'] = book_serializers_obj.data
    else:
        back_dict['code'] = 1001
        back_dict['msg'] = '失败'
        back_dict['error'] = book_serializers_obj.errors
    return Response(back_dict)

当执行book_serializers_obj.save()保存修改后的数据时,会报错:

NotImplementedError: `update()` must be implemented.

说update()方法必须重写,点击save()查看update()源码得:

def update(self, instance, validated_data):
    raise NotImplementedError('`update()` must be implemented')

原来是作者定义时自动把update()写为raise异常

所以我们想要成功修改数据就必须重写update()方法(在定义的序列化类里书写

# 重写update方法
def update(self, instance, validated_data):
    """
    :param instance: 就是当前的queryset对象
    :param validated_data: 校验成功的数据
    """
    instance.id = validated_data.get('id')
    instance.name = validated_data.get('name')
    instance.price = validated_data.get('price')
    instance.author = validated_data.get('author')
    instance.save()
    return instance

之后再发送PUT请求就能修改数据成功了

---序列化组件删除数据

当发送DELETE请求时,删除数据

def delete(self, request, pk):
    # 删除数据无需序列化和反序列化,直接删除即可
    models.Book.objects.filter(pk=pk).delete()
    # 删除成功返回一个空,如果没删除成功会自动抛异常返回一个空
    return Response()

---序列化组件新增数据

当发送post请求时,可以新增数据

def post(self, request):
    back_dict = {'code': 1000, 'msg': '成功'}
    book_serializers_obj = BookSerializers(data=request.data)  # 如果要新增就不需要传instance,按关键字传
    if book_serializers_obj.is_valid():
        book_serializers_obj.save()
        back_dict['data'] = book_serializers_obj.data
    else:
        back_dict['code'] = 1001
        back_dict['msg'] = '失败'
        back_dict['error'] = book_serializers_obj.errors
    return Response(back_dict)

同理,新增数据需要重写create()方法(在定义的序列化类中书写)

def create(self, validated_data): # validated_data为用户上传的数据
    # 通过表对象保存,这样就知道了保存到那张表中
    instance = models.Book.objects.create(**validated_data)  # 打散保存
    # 返回
    return instance

---source使用

在序列化组件时,序列化类中的字段必须与模型表内的字段是对应的

如果序列化时不对应,请求来访问时就会报错。如果想使用别的字段名①,就可以用source

book_name = serializers.CharField(source='name')
# source这可以把它看做Book对象(instance),source='name'就<==>instance.name获取book对象的属性名name传给book_name

source也可以对应模型表中的方法②(方法返回结果是什么,字段对应结果就是什么)

models.py
class Book(models.Model):
    ...

    def get_book_name(self):
        return '四大名著:' + self.name

序列化类
class BookSerializers(serializers.Serializer):
    book_name = serializers.CharField(source='get_book_name')

 当该模型表下还有与其他表相关联的外键字段时,source还支持跨表查询以使外键字段显示相应数据                 主要用来做一对多,多对多的字段返回

models.py
class Book(models.Model):
    ...
    # 与出版社关联
    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE, null=True)

序列化类
class BookSerializers(serializers.Serializer):
    ...
    publish_addr = serializers.CharField(source='publish.address')

 --- SerializerMethodField使用

SerializerMethodField能帮助拿到关联表所有字段的值(如拿到出版社的详细信息)

使用SerializerMethodField就必须指定一个get_字段名的方法,该字段名是SerializerMethodField方法需要序列化的字段

序列化类中
class BookSerializers(serializers.Serializer):
    。。。
    # SerializerMethodField使用 必须搭配一个函数:get_字段名
    publish = serializers.SerializerMethodField()
    def get_publish(self, instance):
        # instance即为book对象
        publish_obj = instance.publish # 跨表到publish对象
        datas_list = [{'name':publish_obj.name,'addr':publish_obj.address}]
        return datas_list

 --- 局部钩子和全局钩子

class BookSerializers(serializers.Serializer):
    。。。

    # 局部钩子 validate_字段名 data为字段对应数据(名字任取)
    def validate_price(self, data):
        if float(data) >= 0:
            return data
        else:
            raise ValidationError('价格非负')

    # 全局钩子 attrs为全部合格数据(名字任取)
    def validate(self, attrs):
        name = attrs.get('name')
        author = attrs.get('author')
        if name == author:
            raise ValidationError('书籍名和作者名字相同')
        else:
            return attrs

--进阶使用

--- 基于GenericAPIView类写views.py中的五个接口函数

效果等价,只是比基于APIView写的代码少。∵都继承APIView,但有了更多方法

models.py
    class Publish(models.Model):
        id = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        address = models.CharField(max_length=64)
        def __str__(self):
            return self.name
urls.py
	# 基于GenericAPIView的关于Publish
	path('publishes/', views.PublishGenericAPIView.as_view()),
	re_path('publishes/(?P<pk>\d+)/', views.PublishGenericAPIViewByPK.as_view()),
views.py
	from rest_framework.generics import GenericAPIView
	class PublishGenericAPIView(GenericAPIView):
	    queryset = models.Publish.objects
	    #queryset = models.Publish.objects跟上面等价的
	    serializer_class = PublishSerializers
	    # 发送get请求查所有
	    def get(self, request):
	        publish_obj = self.get_queryset()
	        publish_serializers_obj = self.get_serializer(publish_obj,many=True)
	        return Response(publish_serializers_obj.data)
	    # 发送post请求 新增数据
	    def post(self, request):
	        publish_serializers_obj = self.get_serializer(data=request.data)        
            if publish_serializers_obj.is_valid():
	            publish_serializers_obj.save() # 需重写create方法吗?——要
	            return Response(publish_serializers_obj.data)
	        else:
	            return Response({'msg':'数据不合要求'})
	class PublishGenericAPIViewByPK(GenericAPIView):
	    queryset = models.Publish.objects
	    serializer_class = PublishSerializers
	    # get请求查单个数据
	    def get(self, request, pk):
	        publish_obj = self.get_object()
	        publish_serializers_obj = self.get_serializer(publish_obj)
	        return Response(publish_serializers_obj.data)
	    # PUT请求修改数据
	    def put(self, request, pk):
	        publish_obj = self.get_object()
	        publish_serializers_obj = self.get_serializer(publish_obj,data=request.data)
	        if publish_serializers_obj.is_valid():
	            publish_serializers_obj.save()  # 需重写updata()方法吗?——要
	            return Response(publish_serializers_obj.data)
	        else:
	            return Response({'msg':'修改后的数据不合格'})
	    # 发送delete请求 删除单个
	    def delete(self, request, pk):
	        self.get_object().delete()
	        return Response({'msg':'删除成功'})

--- 基于GenericAPIView类和五个扩展类写views.py中的五个接口函数

urls.py
	path('publishes/', views.PublishGenericAPIView5others.as_view()),
	re_path('publishes/(?P<pk>\d+)/',  
	                                       views.PublishGenericAPIView5othersByPK.as_view()),
views.py
	from rest_framework.mixins import ListModelMixin,CreateModelMixin,\                                
	                                    UpdateModelMixin,RetrieveModelMixin,DestroyModelMixin
	class PublishGenericAPIView5others(GenericAPIView,ListModelMixin,CreateModelMixin):
	    queryset = models.Publish.objects
	    serializer_class = PublishSerializers
	    def get(self, request):
	        return self.list(request) # 查所有
	    def post(self, request):
	        return self.create(request) # 增
	class PublishGenericAPIView5othersByPK(GenericAPIView,UpdateModelMixin,RetrieveModelMixin,DestroyModelMixin):
	    queryset = models.Publish.objects
	    serializer_class = PublishSerializers
	    def get(self, request, pk):
	        return self.retrieve(request,pk) # 查单个
	    def put(self, request, pk):
	        return self.update(request,pk) # 改
	    def delete(self, request, pk):
            return self.destroy(request,pk) # 删

--- 基于GenericAPIView类的9个子类写views.py中的五个接口函数

urls.py
	path('publishes/', views.PublishGenericAPIView9children.as_view()),
    re_path('publishes/(?P<pk>\d+)/', 
                                             views.PublishGenericAPIView9childrenByPK.as_view()),
views.py
	# 基于GenericAPIView的9个子类 需要用哪个就导哪个 有些类是含两个功能
	from rest_framework.generics import ListAPIView,UpdateAPIView,\
	    CreateAPIView,DestroyAPIView,ListCreateAPIView,RetrieveAPIView,\
	    RetrieveDestroyAPIView,RetrieveUpdateAPIView,RetrieveUpdateDestroyAPIView
	# 查所有 新增 两个使用方式等价
	# class PublishGenericAPIView9children(ListAPIView, CreateAPIView):
	class PublishGenericAPIView9children(ListCreateAPIView):
	    queryset = models.Publish.objects
	    serializer_class = PublishSerializers
	class PublishGenericAPIView9childrenByPK(UpdateAPIView,DestroyAPIView,RetrieveAPIView):
	    queryset = models.Publish.objects
        serializer_class = PublishSerializers

--- 基于ModelViewSet类写views.py中的五个接口函数

urls.py
	path('publishes/', views.PublishModelViewSet.as_view({'get':'list','post':'create'})),
	re_path('publishes/(?P<pk>\d+)/', views.PublishModelViewSet.as_view(actions={'get':'retrieve','put':'update','delete':'destroy'})      # 用关键字命名最好
views.py
	# 基于ModelViewSet写5个接口
	from rest_framework.viewsets import ModelViewSet
	class PublishModelViewSet(ModelViewSet):
	    queryset = models.Publish.objects
        serializer_class = PublishSerializers

--- 自动生成路由

# 第一步 导入routers中的两个类
from rest_framework.routers import SimpleRouter,DefaultRouter
# 第二步 实例化得到对象
router = SimpleRouter() # 自动生成两条路由 一般用它
# router = DefaultRouter() # 自动生成六条路由 不推荐→
# 第三步 注册
# router.register('前缀', 继承ModelViewSet的视图类, [‘别名’])
router.register('publishes', views.PublishModelViewSet) # 不加斜杠/
"""
print(router.urls)
    [<URLPattern '^publishes/$' [name='publish-list']>, 
    <URLPattern '^publishes/(?P<pk>[^/.]+)/$' [name='publish-detail']>]
"""
# 第四步 将自动生成路由加入路由列表中 在urlpatterns下书写
urlpatterns += router.urls

--- action装饰器使用

装饰器action用于给在继承ModelViewSet的视图类中自定义的函数也添加路由

'''views.py'''
from rest_framework.viewsets import ModelViewSet
from rest_framework.decorators import action
class PublishModelViewSet(ModelViewSet):
    queryset = models.Publish.objects
    serializer_class = PublishSerializers

    @action(methods=['get','post'], detail=False)
	"""
	methods是访问此路由时来的可执行请求 不区分大小写 内部自动.lower()
	detail布尔类型 为False时自动路由为publishes/get_all/$ [name='publish-get-all']
	"""
    def get_all(self, request):
        # print(request.method) # 可通过request.method来分别做get请求和post请求的事!
        publish_obj = self.get_queryset()
	     # publish_obj = self.get_queryset()[:10] # 截取,前十条
        publish_ser_obj = self.get_serializer(publish_obj, many=True)
        return Response(publish_ser_obj.data)

    @action(methods=['get'], detail=True)
	"""
	detail为True时 自动生成路由匹配为publishes/(?P<pk>[^/.]+)/get_1/$ [name='publish-get-1']           注意pk在中间
	"""
    def get_1(self, request, pk):
        publish_obj = self.get_object()
        publish_ser_obj = self.get_serializer(publish_obj)
        return Response(publish_ser_obj.data)

总结

一般写序列化组件用APIView原生,可扩展功能多

GenericAPIView用于操作数据库时方便


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weer-wmq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值