Django 使用请求和响应对象在系统中传递状态。
当一个页面被请求时,Django 会创建一个 HttpRequest 对象,这个对象包含了请求的元数据。然后,Django 加载相应的视图,将 HttpRequest 作为视图函数的第一个参数。每个视图负责返回一个 HttpResponse 对象。
下面介绍HttpRequest对象常用的属性和方法。
以上的4个属性是我们最常用的HttpRequest属性。结合实际,我们可能写出的代码如下:
if request.method == "POST": # POST请求方法
try:
data = json.loads(request.body) # 获取POST请求携带的非表单数据(JSON数据)
except json.JSONDecodeError:
return JsonResponse({"status": "1", "msg": "数据格式错误"})
# 表单数据
# keys = request.POST.get("keys") # 如果POST携带的是表单数据,可以这样获取。
elif request.method == "GET":
keys = request.GET.get("keys") # 获取get请求携带的参数
return JsonResponse({"status": "0", "msg": "请求成功"})
else:
return JsonResponse({"status": "0", "msg": "请求方法错误"})
<input type="file" name="">
中的 name。FILES 中的每个值是一个 UploadedFile。
FILES 只有在请求方法是 POST,并且发布请求的<form>
有 enctype=“multipart/form-data” 的情况下,才会包含数据。否则,FILES 将是一个类似字典的空白对象。
请求中的任何 HTTP 头都会被转换为 META 键,方法是将所有字符转换为大写字母,用下划线代替任何连字符,并在名称前加上 HTTP_` 前缀。例如,请求头里的X-CSRFToken在META中变为HTTP_X_CSRFTOKEN.
Django 的 contrib 应用中包含的一些中间件会在请求中设置属性。
如果使用Nginx+uWsgi的方式部署Django项目,那么META中的REMOTE_ADDR,REMOTE_HOST等不正确的,因为通过Nginx代理转发到uWsgi监听的端口,这时候应用程序获取的客户端信息就是127.0.0.1的本机信息,而不是真实客户端的信息。因此,需要在Nginx中添加如下参数:
uwsgi_param Host $host;
uwsgi_param X-Real-IP $remote_addr;
uwsgi_param X-Forwarded-For $proxy_add_x_forwarded_for;
uwsgi_param X-Forwarded-Proto $http_x_forwarded_proto;
至于你需要的到底是X-Real-IP还是X-Forwarded-For,取决于你的业务逻辑。
在一个 HttpRequest 对象中, GET 和 POST 属性是 django.http.QueryDict 的实例,这是一个类似字典的类,用来处理同一个键的多个值。这是很有必要的,因为一些 HTML 表单元素,尤其是<select multiple>
,会传递同一个键的多个值。
在 request.POST 和 request.GET 中的 QueryDict 将在正常的请求/响应周期中被访问时是不可改变的。要得到一个可变的版本,你需要使用 QueryDict.copy()。
QueryDict是字典的子类,因此字典有的标准方法,QueryDict都具备。
下面是一段代码,展示了get和getlist的使用。
>>> qd = QueryDict('a=1&a=2&a=3&b=4') # 构造QueryDict对象qd
>>> qd.get('a') # 获取键a的最后一个值
'3'
>>> qd.getlist('a') # 获取键a的所有值
['1', '2', '3']
>>> qd
<QueryDict: {'a': ['1', '2', '3'], 'b': ['4']}>
>>> qd.getlist('c')
[]
>>> qd.getlist('c', [1,2])
[1, 2]
>>> qd.get('c', '5')
'5'
Django会自动创建HttpRequest(wsgi或者asgi创建)对象, HttpResponse则是后端开发人员负责实例化、填充和返回。每一个视图函数都必须返回一个HttpResponse对象。
HttpResponse类位于django.http模块中。
典型的用法是将页面的内容以字符串、字节字符串或 memoryview 的形式传递给 HttpResponse 构造函数。例如:
>>> from django.http import HttpResponse
>>> response = HttpResponse("Hello World!")
这样,在函数结束的时候return response
前端就能拿到响应数据了。
但如果你想增量添加内容,你可以使用 response 作为一个类似文件的对象:
>>> response = HttpResponse()
>>> response.write("<p>Here's the text of the Web page.</p>")
>>> response.write("<p>Here's another paragraph.</p>")
在前后端分离的大趋势下,我们机会很少使用后端去渲染页面。后端通常都是返回JSON数据。
传入迭代器
你可以传递 HttpResponse 一个迭代器而不是字符串。HttpResponse 将立即消耗迭代器,将其内容存储为一个字符串,然后丢弃它。带有 close() 方法的对象,如文件和生成器,会立即关闭。如果你需要将响应从迭代器流式传输到客户端,你必须使用 StreamingHttpResponse 类来代替。
这种操作在普通场景下没什么问题,但是如果文件或者图片很多,并且很大,通常我们使用一个独立的静态文件服务器来解决问题,而不是由Django来处理这些东西
** 告诉浏览器将响应作为文件附件处理 **
>>> response = HttpResponse(my_data, headers={
... 'Content-Type': 'application/vnd.ms-excel',
... 'Content-Disposition': 'attachment; filename="foo.xls"',
... })
Content-Disposition 头并没有什么 Django 特有的内容,但是很容易忘记语法,所以我们把它包含在这里。
HttpResponse子类可以直接参考Django文档,对于现在而言,最常用的莫过于JsonResponse子类。在此,会专门介绍JsonResponse子类的。
class JsonResponse(data, encoder=DjangoJSONEncoder, safe=True, json_dumps_params=None, **kwargs)
一个 HttpResponse 子类,帮助创建一个 JSON 编码的响应。它继承了它的超类的大部分行为,但有一些不同:
其默认的 Content-Type 头设置为 application/json。
第一个参数 data 应该是 dict 实例。如果 safe 参数设置为 False (见下文),它可以是任何 JSON 可序列化的对象。
encoder,默认为 django.core.serializers.json.DjangoJSONEncoder,将用于序列化数据。
safe 布尔参数默认为 True。如果它被设置为 False,任何对象都可以被传递到序列化中(否则只允许 dict 实例)。如果 safe 为 True,而第一个参数是一个非 dict 对象,则会引发一个 TypeError。
json_dumps_params 参数是一个关键字参数的字典,用来传递给 json.dumps() 调用,用于生成响应。可以用来指定编码。
参考资料