经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Django » 查看文章
django框架之drf:3、API执行流程、Response源码剖析、序列化器的简介和使用、反序列化的校验
来源:cnblogs  作者:kngk  时间:2023/2/1 19:42:35  对本文有异议

Django框架之drf

一、APIView执行流程

基于APIView+JsonResponse接口

  1. 通常在使用django编写CBV的视图类的时候我们都是直接继承View,但在drf内我们会继承drf提供的APIView
  1. # view视图函数
  2. from rest_framework.views import APIView
  3. from .models import Book
  4. from django.http import JsonResponse
  5. class BookView(APIView):
  6. def get(self, request):
  7. book_all_queryset = Book.objects.all()
  8. book_data_dict = [{'name': book_queryset.name, 'price': book_queryset.price, 'publish': book_queryset.publish}
  9. for book_queryset in book_all_queryset]
  10. return JsonResponse(book_data_dict, safe=False)

基于APIView+Response写接口

  1. # view视图函数
  2. from rest_framework.response import Response
  3. from rest_framework.views import APIView
  4. from .models import Book
  5. from django.http import JsonResponse
  6. class BookView(APIView):
  7. def get(self, request):
  8. book_all_queryset = Book.objects.all()
  9. book_data_dict = [{'name': book_queryset.name, 'price': book_queryset.price, 'publish': book_queryset.publish}
  10. for book_queryset in book_all_queryset]
  11. return Response(book_data_dict)
  12. # return JsonResponse(book_data_dict, safe=False

APIView的执行流程

  1. # 路由中写的: path('books/', views.BookView.as_view()),---》请求来了,执行views.BookView.as_view()()----->现在的as_view是APIView的as_view
  2. # APIView的as_view方法:view还是原来的view,但是以后再也没有csrf认证了
  3. @classmethod
  4. def as_view(cls, **initkwargs):
  5. # 调用父类的as_view,父类是django原生的View
  6. # 把djagno原生View的as_view方法中的闭包函数view拿出来了
  7. view = super().as_view(**initkwargs)
  8. # csrf_exempt 排除所有csrf的认证
  9. # 相当于在所有的方法上面加了这个装饰器
  10. return csrf_exempt(view)
  11. # 路由匹配成功,执行 csrf_exempt(view)(requets)--->View的as_view中的闭包函数view---》self.dispatch---->self是视图类的对象---》BookiView---》APIView的dispatch,找到了
  12. def dispatch(self, request, *args, **kwargs):
  13. # request是django原生的request,老的request
  14. # 把老的request包装成了新的request,这个是drf提供的Request类的对象
  15. request = self.initialize_request(request, *args, **kwargs)
  16. # 到此以后,这个request就是新的了,老的request在哪?
  17. # request._request 这是老的
  18. # 把新的request放到了self对象【BookView的对象】
  19. self.request = request
  20. try:
  21. # 执行了三大认证【认证,频率,权限】,使用新的request,不读
  22. self.initial(request, *args, **kwargs)
  23. # 跟之前一毛一样
  24. if request.method.lower() in self.http_method_names:
  25. handler = getattr(self, request.method.lower(),
  26. self.http_method_not_allowed)
  27. else:
  28. handler = self.http_method_not_allowed
  29. # 把新的request传入了,视图类的方法中get的request也是新的
  30. response = handler(request, *args, **kwargs)
  31. except Exception as exc:
  32. # 在执行3大认证和视图类中方法的过程中,如果出了异常,都能捕获到---》全局异常捕获
  33. response = self.handle_exception(exc)
  34. self.response = self.finalize_response(request, response, *args, **kwargs)
  35. return self.response

1、API执行流程总结(重点)

  • 去除了所有的csrf校验
  • 包装了新的request,以后在视图类中使用的request是新的request
    • Request类对象是,不是django原生的对象
    • 原生的对象:request._request
  • 在只执行视图类的方法前,执行了3大认证
    • 如果3大认证或视图函数方法执行过程中出现了错误,会异常捕获

2、补充

在我们使用的装饰器时会在需要添加功能的函数头上装饰语法糖,其实其本质就是将需要添加功能的函数当作参数,传入装饰器中

  1. def auth() # 装饰器
  2. pass
  3. def add() # 函数
  4. pass
  5. # 使用auth装饰add函数
  6. @auth # 本质是 add=auth(add)
  7. def add()
  8. # 以后再使用add,其实就是在使用 auth(add) 的返回结果

二、Response源码剖析

  1. # 新的Request---》区别于老的
  2. # 老的:django.core.handlers.wsgi.WSGIRequest
  3. # 新的:from rest_framework.request import Request
  4. -新的 request._request 是老的
  5. # Request源码
  6. -方法 __getattr__
  7. -在视图类的方法中,执行request.method ,新的request是没有method的,就触发了新的Request__getattr__方法的执行
  8. def __getattr__(self, attr):
  9. try:
  10. # 从老的request中反射出 要取得属性
  11. return getattr(self._request, attr)
  12. except AttributeError:
  13. return self.__getattribute__(attr)
  14. -request.data--->这是个方法,包装成了数据属性
  15. -以后无论postput。。放在body中提交的数据,都从request.data中取,取出来就是字典
  16. -无论是那种编码格式
  17. -request.query_params--->这是个方法,包装成了数据属性
  18. -get请求携带的参数,以后从这里面取
  19. -query_params:查询参数--->restful规范请求地址中带查询参数
  20. -request.FILES--->这是个方法,包装成了数据属性
  21. -前端提交过来的文件,从这里取

1、Response类总结(重点)

  • 新的response用起来和以前一模一样,新的response取不到会触发双下getattr方法,该方法会执行老的response中的方法
  • response.data :所有的编码格式都可以在这里取,只要是body内的数据都可以取
  • request.query_params 就是原来的request._request.GET
  • 上传的文件从request.FILES中取

三、序列化器的介绍和使用

1、序列化

序列化查找多条数据

  • 在app下创建py文件(serializer)用于创建序列化类
  1. # serializer.py--BookSerializer类
  2. from rest_framework import serializers
  3. class BookSerializer(serializers.Serializer):
  4. # 序列化某些字段,这里写要序列化的字典
  5. name = serializers.CharField() # serializers下大致跟models下的类是对应的
  6. # price = serializers.CharField()
  7. publish = serializers.CharField()
  8. # views.py--->BookView类
  9. class BookView(APIView):
  10. def get(self, request):
  11. # 只是为了验证之前讲过的
  12. print(request.method)
  13. print(request._request)
  14. print(type(self.request))
  15. books = Book.objects.all()
  16. # 使用序列化类来完成---》得有个序列化类
  17. # instance要序列化的数据books queryset对象
  18. # many=True 只要是queryset对象要传many=True,如果是单个对象就不用传
  19. ser = BookSerializer(instance=books, many=True)
  20. return Response(ser.data) # 无论是列表还是字典都可以序列化

序列化查找单条数据

  • 之前创建的serializer.py文件不需要修改
  1. # 视图类---》BookDetailView
  2. class BookDetailView(APIView):
  3. # def get(self, request,pk):
  4. def get(self, request, *args, **kwargs):
  5. book = Book.objects.filter(pk=kwargs.get('pk')).first()
  6. # 序列化
  7. ser = BookSerializer(instance=book)
  8. return Response(ser.data)
  9. # url.py中新增路由
  10. urlpatterns = [
  11. path('book/<int:pk>/', views.BookDetailView.as_view()),
  12. ]

2、反序列化

反序列化的新增

  1. # serializer.py(序列化类)
  2. class BookSerializer(serializers.Serializer):
  3. # 序列化某些字段,这里写要序列化的字典
  4. name = serializers.CharField() # serializers下大致跟models下的类是对应的
  5. price = serializers.CharField()
  6. publish = serializers.CharField()
  7. def create(self, validated_data):
  8. # 保存的逻辑
  9. # validated_data 校验过后的数据 {name,price,publish}
  10. # 保存到数据库
  11. book = Book.objects.create(**validated_data)
  12. # 一定要返回新增的对象
  13. return book
  14. # view.py(视图类)
  15. class BookView(APIView):
  16. def post(self, request):
  17. # requset.data # 前端提交的要保存的数据----》校验数据---》存
  18. ser = BookSerializer(data=request.data) # 把前端传入的要保存的数据,给data参数
  19. # 校验数据
  20. if ser.is_valid():
  21. # 保存---->需要自己写,要在序列化类BookSerializer中写----》create方法
  22. ser.save() # 调用ser.save,自动触发咱们写的create,保存起来
  23. return Response({'code': 100, 'msg': '新增成功', 'result': ser.data})
  24. else:
  25. return Response({'code': 101, 'msg': ser.errors})

反序列化的修改

  1. # serializer.py(视图类)
  2. class BookSerializer(serializers.Serializer):
  3. # 序列化某些字段,这里写要序列化的字典
  4. name = serializers.CharField() # serializers下大致跟models下的类是对应的
  5. price = serializers.CharField()
  6. publish = serializers.CharField()
  7. def create(self, validated_data):
  8. # 保存的逻辑
  9. # validated_data 校验过后的数据 {name,price,publish}
  10. # 保存到数据库
  11. book = Book.objects.create(**validated_data)
  12. # 一定不要返回新增的对象
  13. return book
  14. def update(self, instance, validated_data):
  15. # instance 要修改的对象
  16. # validated_data 校验过后的数据
  17. instance.name = validated_data.get('name')
  18. instance.price = validated_data.get('price')
  19. instance.publish = validated_data.get('publish')
  20. instance.save() # orm的单个对象,修改了单个对象的属性,只要调用对象.save,就能把修改保存到数据库
  21. return instance # 不要忘了把修改后的对象,返回
  22. # view.py(视图类)
  23. class BookDetailView(APIView):
  24. def put(self, request, pk):
  25. book = Book.objects.filter(pk=pk).first()
  26. # 反序列化保存 ---借助于序列化类
  27. ser = BookSerializer(data=request.data, instance=book)
  28. if ser.is_valid():
  29. ser.save() # 由于没有重写update,所以这报错
  30. return Response({'code': 100, 'msg': '修改成功', 'result': ser.data})
  31. else:
  32. return Response({'code': 101, 'msg': ser.errors})

删除单条数据

  1. class BookDetailView(APIView):
  2. def delete(self, request, pk):
  3. Book.objects.filter(pk=pk).delete()
  4. return Response({'code': 100, 'msg': '删除成功'})

五、反序列化的校验

? 反序列化类反序列化,数据校验功能--->类比forms组件

局部钩子

? 校验单个字段

  1. from rest_framework import serializers
  2. from rest_framework.exceptions import ValidationError
  3. from .models import Book
  4. class BookSerializer(serializers.Serializer):
  5. name = serializers.CharField()
  6. price = serializers.IntegerField()
  7. publish = serializers.CharField()
  8. def create(self, validated_data):
  9. new_book_queryset = Book.objects.create(**validated_data)
  10. return new_book_queryset
  11. def update(self, instance, validated_data):
  12. instance.name = validated_data.get('name')
  13. instance.price = validated_data.get('price')
  14. instance.publish = validated_data.get('publish')
  15. instance.save()
  16. return instance
  17. def validate_name(self, name):
  18. if not len(name) < 3:
  19. return name
  20. raise ValidationError('书名不能低于三个字符')

全局钩子

? 校验所有字段

  1. from rest_framework import serializers
  2. from rest_framework.exceptions import ValidationError
  3. from .models import Book
  4. class BookSerializer(serializers.Serializer):
  5. name = serializers.CharField()
  6. price = serializers.IntegerField()
  7. publish = serializers.CharField()
  8. def create(self, validated_data):
  9. new_book_queryset = Book.objects.create(**validated_data)
  10. return new_book_queryset
  11. def update(self, instance, validated_data):
  12. instance.name = validated_data.get('name')
  13. instance.price = validated_data.get('price')
  14. instance.publish = validated_data.get('publish')
  15. instance.save()
  16. return instance
  17. def validate(self, attrs):
  18. if len(attrs.get('name')) < 3:
  19. raise ValidationError('书名不能低于三个字符')
  20. try:
  21. float(attrs.get('price'))
  22. except Exception:
  23. raise ValidationError('价格只能是整数或小数')
  24. finally:
  25. if len(attrs.get('publish')) < 3:
  26. raise ValidationError('书名不能低于三个字符')
  27. return attrs

/

原文链接:https://www.cnblogs.com/kangssssh/p/17083984.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号