Django-DRF入门
DRF(Django RestFramework)是基于Django-CBV实现的原生框架(但是支持FBV),实现的Django扩展,可以更加方便的实现前后端分离项目的API开发
DRF支持CBV也支持FBV模式开发
1. pip安装
pip install restframework
2. Django项目中注册
Djano项目-settings.py
INSTALLED_APPS = [
...
'rest_framework',
]
3. DRF-APIView视图
在之前基础的Django类中,我们对于POST-JSON数据的处理,非常的繁杂,需要先request.body在用json.loads进行序列化处理,但是实际体验上,非常的难以使用,DRF的APIView类,是对Django-View的继承,在原有功能上实现更多API相关视图功能。
3.1 使用CBV(类视图)实现APIView
使用CBV视图的APIView只需要在原有定义视图时,让其继承自APIView即可
from rest_framework.views import APIView # 导入APIView类
class User(APIView): # 继承自APIView类
def get(self, request):
get_params = request.query_params # 获取GET请求结果
print(get_params)
return HttpResponse(f'Get请求,数据:{get_params}')
def post(self, request):
post_data = request.data # 获取POST请求结果
print(post_data)
return HttpResponse(f'post请求,数据:{post_data}')
def delete(self, request):
delete_data = request.data # 获取delete请求的body
print(delete_data)
return HttpResponse(f'delete请求,数据:{delete_data}')
3.2 使用FBV(函数视图)实现
一般在DRF中,我们以CBV为主,可以实现更多扩展,FBV在这里仅仅作为扩展,可以更加快速的创建视图。
from rest_framework.decorators import api_view
from rest_framework.response import Response
@api_view(['GET', 'POST'])
def my_view(request):
if request.method == 'GET':
# 处理GET请求逻辑
return Response({"message": "这是GEI请求"})
elif request.method == 'POST':
# 处理POST请求逻辑
return Response({"message": "这是POST请求"})
可以发现FBV模式使用装饰器创建,从表面看,其实和Flask的app.route非常相似,但是我们深究源码可以发现,其实本质上也是CBV实现
FBV-api_view装饰器源码(这里只展示重要部分)
# api_view源码重点
def api_view(http_method_names=None):
def decorator(func):
WrappedAPIView = type(
'WrappedAPIView',
(APIView,),
{'__doc__': func.__doc__}
)
......
......
# 其他逻辑代码省略
return WrappedAPIView.as_view()
return decorator
通过上述展示,其实可以看出来,使用type创建了一个类(可以理解为代替class直接创建了一个类),创建的是继承于APIView的WrappedAPIView类,所以FBV模式的api-view,其实是DRF帮忙封装的。
4. DRF中的Request(请求)对象
DRF中Request对象所在包:
from rest_framework.request import Request
Django中Request对象所在包:
from django.http import HttpRequest
4.1 请求对象的各类属性
它是Django的HttpRequest对象的一个扩展,提供了更多与RESTful API相关的功能和数据。
DRF中的请求对象有以下常用的属性和方法:
- request.method: 表示HTTP请求的方法,例如"GET"、“POST”、“PUT”、"DELETE"等。
- request.query_params: 一个类似于字典的属性,包含GET请求的查询参数。例如,对于URL “/api/resource/?page=1&size=10”,可以通过
request.query_params["page"]
获取到值为1的查询参数。 - request.data: 类似于字典的属性,包含POST、PUT等请求的数据。对于JSON格式的请求数据,可以通过
request.data["key"]
获取特定字段的值。 - request.GET: 一个类似于字典的属性,包含GET请求的查询参数。与
request.query_params
相同,用于获取GET请求的查询参数。 - request.POST: 一个类似于字典的属性,包含POST请求的表单数据。通过
request.POST["key"]
可以获取POST请求中的字段值。 - request.FILES: 一个类似于字典的属性,包含上传的文件。当表单中有文件上传时,可以通过
request.FILES["file_field_name"]
获取上传的文件对象。 - request.user: 表示当前请求的用户对象。如果使用了身份认证和授权,
request.user
将是认证通过的用户对象。 - request.auth: 表示当前请求的认证对象。如果启用了身份认证,
request.auth
将包含认证的相关信息。 - request.content_type: 表示请求的Content-Type头部,指示请求数据的格式(例如,application/json或multipart/form-data等)。
- request.accepted_renderer: 表示DRF选择的渲染器,用于确定响应数据的格式。可以用于在视图中根据请求头部选择不同的响应渲染器。
- request.accepted_media_type: 表示请求的Accept头部,指示客户端可以接受的响应数据格式。
4.2 常用属性解析
4.2.1 .query_params解析(和request.GET相同)
用户获取请求中的URL_params,任何类型请求都有该方法
其实本质上,就是对Django原生HttpRequest对象中.GET方法的继承
使用方法(均以CBV做解释):
# url -> /api/resource/?page=1&size=10 # path示例
def get(self,request):
print(request.query_params)
->>> <QueryDict: {'page': ['1'],'size':['10']}> # 返回QueryDict(类似字典)
print(request.query_params.get('page'))
->>> '1'
print(request.query_params.values())
->>> dict_keys(['page','size']) # 字典keys对象
源码解析:
@property # 定义为属性方法,可以不带括号调用
def query_params(self):
return self._request.GET
# 本质上就是返回了Django原生的HttpRequest,所以使用方法与原生相同
4.2.2 .data解析
.data是用于处理请求体的方法,POST,PUT,PATCH,DELETE等请求会存在请求体
其实本质上,就是对Django原生HttoRequest对象中原本.bode方法的序列化
之前我们使用Django解析JSON总是需要自己使用json.loads,而DRF帮我们做了封装,并且表单数据以及JSON均可以解析
@property # 定义为属性方法,可以不带括号调用
def data(self):
if not _hasattr(self, '_full_data'):
self._load_data_and_files()
# 如果没有_full_data就调用load_data解析文件或者数据,其实就是将json字符串转换为QuertDict类型
return self._full_data
使用方法:
# url -> /api/user/?page=1&size=10 # path示例
# body:{
"name":"张三"
}
def post(self,request):
print(request.query_params)
->>> <QueryDict: {'page': ['1'],'size':['10']}> # 返回QueryDict
print(request.data)
->>> <QueryDict: {'name': '张三'}> # 返回QueryDict
-------------------------------
# 如果传入不是JSON是表单
# body: name=张三&age=20
# .data仍然能够解析
def post(self,request):
print(request.data)
->>> <QueryDict: {'name': ['张三'],"age":"20"}> # 返回QueryDict
print(request.data.get('name'))
->>> '张三'