IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> Drf从入门到精通二(APIView基本使用、API源码分析、Request类源码分析、序列化与反反序列化) -> 正文阅读

[Python知识库]Drf从入门到精通二(APIView基本使用、API源码分析、Request类源码分析、序列化与反反序列化)

一、APIView基本使用

首先Drf是一个Django第三方的App 它只适用于Django 如果使用到别的框架是使用不了的
安装Drf之后就可以导入一个视图累APIView 所以要使用Drf写视图类 都要继承APIView以及其子类
在安装完Drf(DjangoRestFrameWork)它会默认把系统的Django版本更新到最新 这个时候运行会报错 只要把Drf或者Django版本降低即可

	首先展示使用View展示接口
	
		path('movies/', MovieView.as_view())
		
		class Movie(models.Model):
		    name = models.CharField(max_length=32)
		    price = models.CharField(max_length=32)
		    director = models.CharField(max_length=32)	
		
		class MovieView(View):
		    def get(self, request):
		        movie_list = Movie.objects.all()
		        res_list = []
		        for movie in movie_list:
		            res_list.append({'name': movie.name, 'price': movie.price, 'director': movie.director})
		        return JsonResponse(res_list, safe=False, json_dumps_params={'ensure_ascii': False})
		    '''
		        JsonResponse只能序列化字典以及列表 safe如果是True会抛出异常
		        json_dumps_params={'ensure_ascii': False}把数据转换成中文
		        movie_list是一个queryset对象不能直接序列化 只能通过for循环一个一个拼成列表套字典形式
		    '''
			
		访问结果:[{"name": "今天你做了嘛?", "price": "999", "director": "Mr.Mei"},
				 {"name": "我也想做!", "price": "666", "director": "Mr.Jin"}]


	使用APIView+Response展示接口
	
		from rest_framework.views import APIView
		from rest_framework.response import Response
		# Drf的视图类比较规范 导入都有单独的模块
		
		class MovieView(APIView):
		    def get(self, request):
		        # print(type(self.request))  # 新的request
		        # print(type(request))
		        print(request._request)  # <WSGIRequest: GET '/movies/'>
		        print(type(request._request))  # django.core.handlers.wsgi.WSGIRequest
		
		        # print(request.method)  # get
		        # print(request.path)  # /movies/
		        # print(request.GET)  # 原来的get请求提交的参数
		        # print(request.POST)  # 原来post请求提交的参数
		
		        movie_list = Movie.objects.all()
		        # book_list是queryset对象不能直接序列化,只能通过for循环一个个拼成列表套字典的形式
		        res_list = []
		        for movie in movie_list:
		            res_list.append({'name': movie.name, 'price': movie.price, 'director': movie.director})
		        return Response(res_list)
		
			'''
				注意一定到在Settings里面注册Drf这个app 如果不注册用浏览器访问会报错
				如果注册了使用浏览器浏览就会看到一个被美化的界面 不仅仅是Json格式的数据
			'''

在这里插入图片描述

二、APIView源码分析


	首先入口APIView
		class MovieView(APIView):
		# 进入源码查看as_view 把多余的源码删除看主要的 首先看自身在看继承的
		  @classmethod
	    def as_view(cls, **initkwargs): 
	        view = super().as_view(**initkwargs)
	        return csrf_exempt(view)
	  # 第一层就做了一件事Super调用了父类的as_view把自己的参数传递的了进去 然后把所有的请求csrf检验去除了
	所以请求来了路由匹配成功会执行View类里面的as_view类方法内的View闭包函数实际上还是view的as_view没有csrf验证
		# 再点进继承的view类里面查看 真正执行的是self.dispatch
	          def view(request, *args, **kwargs):
	            return self.dispatch(request, *args, **kwargs)
	   # 再点进来查看dispatch的流程
	      def dispatch(self, request, *args, **kwargs):
	      # 参数的request是Django原生的request
	      # 下面的request变成了Drf提供的Request类的对象不是原生的了
	        request = self.initialize_request(request, *args, **kwargs)
	        self.request = request
	        # self是视图类的对象 视图类对 request=request 新的request
	        self.headers = self.default_response_headers  
	        try:
	          	# 执行了认证 频率 权限「暂时不读后面回进行详细读」
	            self.initial(request, *args, **kwargs)
	            # 这个就跟原来的那个View类的dispatch 判断当前是否拥有八大方法如果有则执行
	            if request.method.lower() in self.http_method_names:
	                handler = getattr(self, request.method.lower(),
	                                  self.http_method_not_allowed)
	            else:
	                handler = self.http_method_not_allowed
	            response = handler(request, *args, **kwargs)
	        except Exception as exc:
	          # 如果出现了异常 就异常捕获 处理异常正常返回
	          # 在执行三大认证和视图类中方法过程中 如果出了异常 是能被捕获并处理的 全局异常的处理
	            response = self.handle_exception(exc)
	        self.response = self.finalize_response(request, response, *args, **kwargs)
	        return self.response
	  
	  
	      # 总结:
	    	1 只要继承APIView都没有csrf的认证了
	        2 以后视图类中使用的request对象,已经变成了drf提供的Request类的对象了
	        3 执行视图类的方法之前,执行了3大认证(认证,权限,频率)
	        4 在执行三大认证和视图类的方法过程中只要报错,都会被捕获处理

三、Request类源码分析


		#1  视图类中使用的request对象 已经变成了drf提供的Request类的对象了
			-原生djagno 的request是这个类的对象:django.core.handlers.wsgi.WSGIRequest
		    -drf的request是这个类的对象:rest_framework.request.Request
		    
		#2 request已经不是原来的request了 还能像原来的request一样使用吗?
			-用起来,像之前一样
		        print(request.method)  # get
		        print(request.path)  # /movies/
		        print(request.GET)   # 原来的get请求提交的参数
		        print(request.POST)  # 原来post请求提交的参数
		        
		        
		#3 Request的源码分析:rest_framework.request.Request
			-类中有个魔法方法:__getattr__    对象.属性,属性不存在会触发它的执行
			def __getattr__(self, attr): # 如果取的属性不存在会去原生django的request对象中取出来
		        try:
		            #反射:根据字符串获取属性或方法 self._request 是原来的request
		            return getattr(self._request, attr)
		        except AttributeError:
		            return self.__getattribute__(attr)
		        
		    -以后用的所有属性或方法,直接用就可以了---》(通过反射去原来的request中取的)
		    
		    -新的request内部有个老的request 就是 request._request
		    
		    -data 是个方法,被property装饰了,变成了数据属性用
		    	-以后body体中提交的数据,都从这里取(request.POST)
		        -urlencoded,form-data:提交的数据在request.POST中
		        -json格式提交的数据,在requets.POST中没有 它在request.body中
		    	-现在无论那种格式,都从request.data中取
		    -query_params:get请求提交的参数 等同于request._request.GET 或  request.GET
		    -其他:取文件也是从request.FILES中取 跟之前一样
		    
		    
		验证 原生requets.POST 只有urlencoded和form-data格式提交的数据 json格式提交的数据在body中
		拿出来自己处理 但是drf的request中有个data data中可以取到任意编码提交的数据
		
		request.data  有时候是(urlencoded,form-data)QueryDict 有时候(json)是字典
		    
		# 4 什么是魔法方法?
			1 在类中只要以__开头 __结尾的都称之为魔法方法
		    2 这种方法不需要手动调用,某种情况会自动触发
		    3 讲过的: __init__,__str__,__call__,......
		    

四、序列化组件介绍

咱在写电影接口的时候涉及到一个问题 要把Queryset单个Movie对象转换成Json格式字符串给前端这个过程就叫做序列化
要是我们现在只要电影名以及导演呢?(就得去删除或者添加)于是Drf就给我们提供了一种可以快速实现序列化的类就跟Forms很像了

	基于APIView+Response+序列化类写接口
	
		创建一个文件 serializer.py
		
			from rest_framework.serializers import Serializer
			from rest_framework import serializers
			
			class MovieSerializers(serializers.Serializer):
			    name = serializers.CharField()
			    price = serializers.CharField()
			    director = serializers.CharField()
			    # 新增数据直接再写一个字段 删除直接删除即可 字段类里面可以写很多字段属性
			    
		views
			from rest_framework.views import APIView
			from rest_framework.response import Response
			from .serializer import MovieSerializers
			
			class MovieView(APIView):
			    def get(self, request):
			        movie_list = Movie.objects.all()
			        # instance表示要序列化的数据,many=True表示序列化多条(instance是qs对象,一定要传many=True)
			        ser = MovieSerializers(instance=movie_list, many=True)
			        return Response(ser.data)
			        
		'''这个时候我们如果需要添加一条数据在类里面添加字段即可 如果想不要删除掉即可 这就非常的方便'''

在这里插入图片描述

五、序列化组件基本使用

	urls.py
		urlpatterns = [
		    path('admin/', admin.site.urls),		# 自带管理员
		    path('movies/', MovieView.as_view()),	# 获取多条数据
		    path('movies/<int:pk>/', MovieDetailView.as_view()),	# 获取单条数据
		]
	
	views.py
		from rest_framework.views import APIView
		from rest_framework.response import Response
		from .serializer import MovieSerializers
		
		class MovieView(APIView):       # 获取多条数据
		    def get(self, request):
		        movie_list = Movie.objects.all()
		        # instance表示要序列化的数据,many=True表示序列化多条(instance是qs对象,一定要传many=True)
		        ser = MovieSerializers(instance=movie_list, many=True)
		        # instance产生一个对象赋值接收 many通过字面都知道什么意思就是获取更多many=True
		        return Response(ser.data)
		
		
		class MovieDetailView(APIView):     # 获取单条数据
		    def get(self, request, pk):
		        movie = Movie.objects.filter(pk=pk).first()
		        ser = MovieSerializers(instance=movie)
		        return Response(ser.data)

	'''
	获取单条与获取多条的方式都是Get 但是如果多条与单条一起使用混合度比较高 所以单独重写一个获取单条的类
	我们发送Get请求单条数据都会跟上ID号所以基本格式是这样 http://127.0.0.1:8000/movies/1/ 所以要在类中添加到ID才能获取到哪一条数据
	'''
		        

在这里插入图片描述

六、反序列化基本使用

		序列化就是查询多个以及查询单个 但是反序列化就是新增和修改了 删除直接删除即可不涉及到序列化
		
		新增
			
		class MovieView(APIView):  # 获取多条数据
		    def get(self, request):
		        movie_list = Movie.objects.all()
		        # instance表示要序列化的数据,many=True表示序列化多条(instance是qs对象,一定要传many=True)
		        ser = MovieSerializers(instance=movie_list, many=True)
		        return Response(ser.data)
		
		    def post(self, request):
		        ser = MovieSerializers(data=request.data)  # 从前端传递数据从request.data中取出来
		        if ser.is_valid():  # is_valid表示校验前端传入的数据 但是我们没有写入校验规则
		            ser.save()  
		            
		           ''' 这个时候发送post请求会发生报错 NotImplementedError: `create()` must be implemented.
		            这个时候点击我们点击save查看源码是调用了Save会触发BaseSerializer的方法
		            判断了 如果instance有值执行update,没有值执行create 看到create没有写 所以我们得重写Create'''
	
		            return Response(ser.data)
		        else:
		            return Response(ser.errors)
			
			'''重写create方法'''
			class MovieSerializers(serializers.Serializer):
			    name = serializers.CharField()
			    price = serializers.CharField()
			    director = serializers.CharField()
			
			    def create(self, validated_data):
			        res = Movie.objects.create(**validated_data)
			        return res
	            

在这里插入图片描述
在这里插入图片描述

		修改
			class MovieDetailView(APIView):  # 获取单条数据
			    def get(self, request, pk):
			        movie = Movie.objects.filter(pk=pk).first()
			        ser = MovieSerializers(instance=movie)
			        return Response(ser.data)
			
			    def put(self, request, pk):
			        movie = Movie.objects.filter(pk=pk).first()
			        ser = MovieSerializers(instance=movie, data=request.data)
			        if ser.is_valid():
			            ser.save()      # 跟上方的新增一样 我们需要去重写update方法
			            return Response(ser.data)
			        else:
			            return Response(ser.errors)
		
				# 重写update方法
			    def update(self, instance, validated_data):
			        instance.name = validated_data.get('name')
			        instance.price = validated_data.get('price')
			        instance.director = validated_data.get('director')
			        instance.save()
			        return instance
			    # instance要修改的对象    validated_data校验过后的数据


		删除
		    def delete(self, request, pk):
		        Movie.objects.filter(pk=pk).delete()
		        return Response()

在这里插入图片描述

技术小白记录学习过程,有错误或不解的地方请指出,如果这篇文章对你有所帮助请点点赞收藏+关注谢谢支持 !!!

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2022-09-30 00:49:11  更:2022-09-30 00:51:28 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 6:48:59-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码