【0】前提概要
【1】基于 View + JsonResponse 编写的 5 个接口:
- 序列化自定义处理: 你需要自己编写序列化逻辑。
- 处理 JSON 格式的 POST 请求数据: 从
request.body
中获取数据,并使用json.loads()
解析成字典,然后创建相应的对象。 - request.POST 和 QueryDict 的区别:
request.POST
返回的是 Django 的QueryDict
对象,与真正的 Python 字典有些差别。您可以通过request.POST.dict()
方法将其转换为纯字典。 - 处理 PUT 请求的数据: PUT 请求的数据不会像 POST 请求那样自动放在
request.PUT
中,您需要自己从request.body
中提取数据,并进行必要的解析(例如,URL 编码和解码)。 - 禁用 CSRF 校验: 注释掉 CSRF 校验,可以在视图函数或者中间件中进行。
-1 序列化需要自己做
-2 post提交数据,如果是json格式,在request.POST取不到数据--》request.body
dic=json.loads(request.body) # request.body bytes格式
Book.objects.create(**dic)
-3 **request.POST--->QueryDict-->跟真正字典有差距
request.POST.get('name') # {name:[lqz,justin]}
request.POST['name']
request.POST.getlist('name')
看源码:from django.http.request import QueryDict
request.POST.dict()--->纯字典--》**
-4 put请求请求体中的数据--》不会放在request.PUT-->自己从body中转--》url编码和解码
django.core.handlers.wsgi.WSGIRequest
-5 注释掉csrf
【2】基于 APIView + Response 编写的 5 个接口:
- 禁用 CSRF 校验: 可以通过在视图函数中使用
@csrf_exempt
装饰器来禁用 CSRF 校验。 - 使用装饰器包装视图函数: 您可以编写一个装饰器函数,在其中调用视图函数,并在装饰器中处理一些通用的逻辑,例如异常处理或者权限验证。
-1 没有csrf校验了---》
@wrapper
def index()
--------------
wrapper(index)
【3】基于 APIView + Response + 序列化类 编写的 5 个接口:
- 编写序列化类: 您需要编写一个继承自
serializers.Serializer
的序列化类,定义需要序列化的字段。 - 反序列化校验: 你可以通过字段自定义校验、局部钩子或全局钩子来实现反序列化时的数据校验。
- 反序列化保存: 在校验通过后,可以调用序列化器的
save
方法来保存数据,可以根据instance
的有无来判断是创建新对象还是更新现有对象。
-1 序列化:写个序列化类,继承Serializer--》写字段--》在视图类中实例化得到对象--》instance,data--》ser.data
serializer.dat ---> 不是json格式字符串 ---> 字典或者列表 ---> Response ----> json格式字符串
-2 反序列化校验:(从上往下)
-1 字段自己的
-2 局部钩子 返回值
-3 全局钩子 返回值
-3 反序列化保存
-1 校验过后 ser.save --->修改,新增
-2 序列化列中重写 create和update--》都是调用save,但是根据instance有没有决定触发create还是update
【一】全局钩子跟局部钩子
全局钩子(Global Hooks)和局部钩子(Local Hooks)通常是指在软件开发中使用的两种不同类型的钩子机制。
【1】全局钩子:
- 全局钩子是在整个应用程序中生效的钩子,它们会影响应用程序的所有部分。
- 全局钩子通常用于在应用程序启动或某个特定事件发生时执行某些操作,例如在每个 HTTP 请求处理之前或之后执行某些代码。
- 在 Web 开发中,全局钩子通常是通过中间件(Middleware)实现的。中间件可以拦截 HTTP 请求和响应,允许开发者在处理请求之前或之后执行自定义代码。
- 例如,在 Django 中,可以编写中间件来实现全局钩子,这些中间件可以在请求处理的不同阶段执行自定义操作,如身份验证、日志记录等。
全局钩子示例(使用 Django 中间件)
class RequestLoggingMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# 在请求处理之前执行的代码
# 记录请求信息到日志文件
logger.info(f"Request: {request.method} {request.path}")
response = self.get_response(request)
# 在请求处理之后执行的代码
return response
-
然后,在 Django 的设置文件中注册这个中间件:
# settings.py MIDDLEWARE = [ # 其他中间件... 'task_api.middleware.RequestLoggingMiddleware', ]
【2】局部钩子:
- 局部钩子是针对特定组件或功能的钩子,只在特定的代码段或功能范围内生效。
- 局部钩子通常用于在特定事件发生时执行某些定制逻辑,例如在模型保存之前或之后执行一些操作。
- 在软件开发中,局部钩子可以通过回调函数、事件监听器或钩子函数等方式实现。
- 例如,在 Django 的模型中,可以利用信号(Signals)实现局部钩子,通过监听模型的特定事件(如
pre_save
、post_save
等),在事件发生时执行相应的操作。
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from Api01.models import Book
class BookSerializer(serializers.Serializer):
name = serializers.CharField()
price = serializers.IntegerField()
publish = serializers.CharField()
# 局部钩子
# 1 数据校验第一层,字段自己校验
# 2 书名不能以sb开头--》局部钩子函数--》给某个字段加限制条件
def validate_name(self, name):
# if name.startswith('sb'):
if 'jni' in name:
# 不合法,抛异常
raise ValidationError('书名不能以jni开头')
else:
# 合法,返回原来的数据
return name
小结:
总的来说,全局钩子用于影响整个应用程序的行为,而局部钩子用于在特定场景下执行定制化逻辑。在设计和开发应用程序时,合理地使用全局钩子和局部钩子可以提高代码的灵活性和可维护性。
对单个字段进行校验的方法是局部钩子,而对多个字段进行校验的方法是全局钩子。
【二】APIView源码执行流程
【1】执行流程
当你使用 Django REST Framework 中的 APIView 类时,它提供了一个用于处理 HTTP 请求的类视图,允许你自定义逻辑来响应不同类型的请求(如 GET、POST、PUT、DELETE 等)。让我们来看一下 APIView 的源码执行流程,并结合具体示例来解释:
- 初始化视图类:当你定义一个继承自 APIView 的类视图时,首先会创建这个类的实例对象。在这个阶段,会执行类的初始化方法
__init__
。 - 请求分发:当有请求到达时,Django 框架会根据请求的方法(GET、POST、PUT 等)调用对应的方法处理请求。APIView 类中提供了一系列方法来处理不同类型的请求,如
get()
、post()
、put()
、delete()
等。 - 请求前处理(dispatch):在调用对应的请求处理方法之前,会先调用
dispatch()
方法进行一些通用的请求预处理操作。这个方法可以被子类重写以添加自定义的请求预处理逻辑。例如,你可以在这个方法中进行身份验证、权限检查等操作。 - 请求处理:根据请求的 HTTP 方法,调用对应的请求处理方法,例如
get()
、post()
、put()
、delete()
等。 - 请求后处理:在请求处理方法执行完毕后,会进行一些请求后处理操作,比如返回响应数据、设置响应头等。
- 返回响应:请求处理方法执行完毕后,会返回一个响应给客户端。
- 结束:整个请求处理过程结束。
-1 请求来:BookView.as_view()(request)-->APIView的as_view--》去除了csrf--》其它跟之前一样(super.super().as_view)--->最终本质就是执行--》self.dispatch-->self 是视图类的对象--》找到APIView的dispatch
-2 APIView的dispatch
def dispatch(self, request, *args, **kwargs):
# 1 包装新的request--》从此后,request就是新的了
request = self.initialize_request(request, *args, **kwargs)
# 2 request新的request放到了self.request中了 【self是视图类的对象】
self.request = request
try:
# 3 执行三大认证
self.initial(request, *args, **kwargs)
#self.perform_authentication(request)
#self.check_permissions(request)
#self.check_throttles(request)
# 3 执行跟请求方式同名的方法
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
# drf的Response
response = handler(request, *args, **kwargs)
except Exception as exc:
# 4 统一处理一场--》统一返回格式
response = self.handle_exception(exc)
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
【2】drf 配置文件之查找顺序
在apiView中使用了drf配置文件的默认配置。以下是配置的查找顺序。
'''方式三:查找顺序(一般就用内置的即可)
1. 视图类 (局部配置)
2. django settings (全局配置)
3. drf api_settings (内置配置)
说明:
优先使用视图类中renderer_classes的配置,其次使用django项目配置文件settings中的配置,最后使用drf内置的api_settings的配置'''
在django的settings中应该按照如下格式写:
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [ # 配置响应
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.TemplateHTMLRenderer',
],
'DEFAULT_PARSER_CLASSES': [ # 配置请求
'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
'rest_framework.parsers.MultiPartParser',
],
}
# 注意:所有配置都写在一个REST_FRAMEWORK里面!
【三】drf之请求
【1】APIView之请求相关配置
# 为什么需要进行请求相关配置?
可以定制某些CBV只能只能接收json格式,不能接收其他格式。也就是为了自定义该接口可接受编码格式。
# 默认情况下
前端上传json request.data里面是 ---> python字典
前端上传urlencode\formdata request.data里面是 ---> QueryDict
# 方式一,在继承自APIView及其子类的的视图类中配置(局部配置)
# 总共有三个:from rest_framework.parsers import JSONParser,FormParser,MultiPartParser
class BookView(APIView):
parser_classes = [JSONParser,]
# 方式二:在配置文件中配置(影响所有,全局配置)
-django有套默认配置,每个项目有个配置
-drf有套默认配置,每个项目也有个配置---》就在django的配置文件中
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': [
# 'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
# 'rest_framework.parsers.MultiPartParser',
],
}
# 方式三:全局配了1个,某个视图类想要3个,怎么配?
-只需要在视图类,配置3个即可
-因为:先从视图类自身找,找不到,去项目的drf配置中找,再找不到,去drf默认的配置找
# 视图类方法中的request
-data
-__getattr__
-query_params
【四】drf之响应
【1】APIView之响应相关配置
# 为什么要在CBV中设置响应相关配置?
因为对于drf的响应,如果使用浏览器和postman访问同一个接口,Response返回的格式是不一样的
-drf做了个判断,如果是浏览器,好看一些,如果是postman只要json数据
# 方式一:在视图类中写(局部配置)
-两个响应类---》找---》drf的配置文件中找--》两个类
-from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer
class BookView(APIView):
renderer_classes=[JSONRenderer,]
# 方式二:在项目配置文件中写(全局配置)
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
],
}
# 方式三:使用顺序(一般就用内置的即可)
1. renderer_classes
2. django settings
3. drf api_settings
说明:
优先使用视图类中renderer_classes的配置,其次使用django项目配置文件settings中的配置,最后使用drf内置的api_settings的配置
【2】Response对象属性
# drf 的Response 源码分析
-from rest_framework.response import Response
-视图类的方法返回时,retrun Response ,走它的__init__, init中可以传什么参数
-Responses最终继承httpresponse.
# Response init可以传的参数
def __init__(self,
data=None,
status=None,
template_name=None,
headers=None,
exception=False,
content_type=None)
-data:之前咱们写的ser.data 可以是字典或列表,字符串---》序列化后返回给前端---》前端在响应体中看到的就是这个
-status: http响应的状态码,默认是200,你可以改
-drf在status包下,把所有http响应状态码都写了一遍,常量
-from rest_framework.status import HTTP_200_OK
-Response('dddd',status=status.HTTP_200_OK)
-template_name:了解即可,修改响应模板的样子,BrowsableAPIRenderer定死的样子,后期公司可以自己定制
-headers:响应头,http响应的响应头 示例:header={'xxx':'yyy'}
-content_type :响应编码格式,一般不动
# 重点:data,status,headers
# 原生djagno,如何在响应头中加东西?
'''
四件套 render,redirect,HttpResponse,JsonResponse
方法: 产生HttpResponse然后添加属性
'''
# 示例:
obj = HttpResponse('dddd')
obj['xxc'] = 'yyc'
return obj
响应头添加属性涉及知识 ---> 跨域