Python Django请求和响应对象详解

时间:2021-07-03 04:40:12

Django请求和响应对象

Django 使用请求和响应对象在系统中传递状态。

当一个页面被请求时,Django 会创建一个 HttpRequest 对象,这个对象包含了请求的元数据。然后,Django 加载相应的视图,将 HttpRequest 作为视图函数的第一个参数。每个视图负责返回一个 HttpResponse 对象。

HttpRequest对象

下面介绍HttpRequest对象常用的属性和方法。

HttpRequest常用属性

1.HttpRequest.body

原始的 HTTP 请求体作为一个字节字符串。这对于以不同方式处理非常规 HTML 表单的数据很有用:二进制图像,XML 有效负载等。对于处理传统的表单数据,使用 HttpRequest.POST

2.HttpRequest.method

代表请求中使用的 HTTP 方法的字符串,一定是大写字母。

3.HttpRequest.GET

一个类似字典的对象,包含所有给定的 HTTP GET 参数。

4.HttpRequest.POST

一个类似字典的对象,包含所有给定的 HTTP POST 参数,前提是请求包含表单数据。如果你需要访问请求中发布的原始或非表单数据,可以通过 HttpRequest.body 属性来访问。

以上的4个属性是我们最常用的HttpRequest属性。结合实际,我们可能写出的代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
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": "请求方法错误"})

5.HttpRequest.COOKIES

一个包含所有 cookies 的字典。键和值是字符串。

6.HttpRequest.FILES

一个类似字典的对象,包含所有上传的文件。FILES 中的每个键是<input type="file" name=""> 中的 name。FILES 中的每个值是一个 UploadedFile。

FILES 只有在请求方法是 POST,并且发布请求的<form>有 enctype=“multipart/form-data” 的情况下,才会包含数据。否则,FILES 将是一个类似字典的空白对象。

7.HttpRequest.META

一个包含所有可用的 HTTP 头文件的字典。可用的头信息取决于客户端和服务器。一些可能的例子如下:

1.CONTENT_LENGTH —— 请求体的长度(字符串)。

2.CONTENT_TYPE —— 请求体的 MIME 类型。

3.HTTP_ACCEPT —— 可接受的响应内容类型。

4.HTTP_ACCEPT_ENCODING —— 可接受的响应编码。

5.HTTP_ACCEPT_LANGUAGE —— 可接受的响应语言。

6.HTTP_HOST —— 客户端发送的 HTTP 主机头。

7.HTTP_REFERER —— referrer 页面,如果有的话。

8.HTTP_USER_AGENT —— 客户端的用户代理字符串。

9.QUERY_STRING —— 查询字符串,是一个单一的(未解析的)字符串。

10.REMOTE_ADDR —— 客户机的 IP 地址。

11.REMOTE_HOST —— 客户机的主机名。

12.REMOTE_USER —— Web 服务器认证的用户,如果有的话。

13.REQUEST_METHOD —— “GET” 或 “POST” 等字符串。

14.SERVER_NAME —— 服务器的主机名。

15.SERVER_PORT —— 服务器的端口(字符串)。

请求中的任何 HTTP 头都会被转换为 META 键,方法是将所有字符转换为大写字母,用下划线代替任何连字符,并在名称前加上 HTTP_` 前缀。例如,请求头里的X-CSRFToken在META中变为HTTP_X_CSRFTOKEN.

中间件设置的属性

Django 的 contrib 应用中包含的一些中间件会在请求中设置属性。

1.HttpRequest.session

来自 SessionMiddleware。一个可读可写的,类似字典的对象,代表当前会话。

2.HttpRequest.user

从 AuthenticationMiddleware。AUTH_USER_MODEL 的一个实例,代表当前登录的用户。如果用户当前没有登录,user 将被设置为一个 AnonymousUser 的实例。你可以用 is_authenticated 来区分它们,例如:

?
1
2
3
4
if request.user.is_authenticated:
    ... # Do something for logged-in users.
else:
    ... # Do something for anonymous users.

如果使用Nginx+uWsgi的方式部署Django项目,那么META中的REMOTE_ADDR,REMOTE_HOST等不正确的,因为通过Nginx代理转发到uWsgi监听的端口,这时候应用程序获取的客户端信息就是127.0.0.1的本机信息,而不是真实客户端的信息。因此,需要在Nginx中添加如下参数:

?
1
2
3
4
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,取决于你的业务逻辑。

QueryDict对象

在一个 HttpRequest 对象中, GET 和 POST 属性是 django.http.QueryDict 的实例,这是一个类似字典的类,用来处理同一个键的多个值。这是很有必要的,因为一些 HTML 表单元素,尤其是<select multiple>,会传递同一个键的多个值。

在 request.POST 和 request.GET 中的 QueryDict 将在正常的请求/响应周期中被访问时是不可改变的。要得到一个可变的版本,你需要使用 QueryDict.copy()。

QueryDict方法

QueryDict是字典的子类,因此字典有的标准方法,QueryDict都具备。

1.QueryDict.get(key, default=None)

?
1
如果键不存在,则用钩子返回一个默认值。如果键有多个值,则会获取到最后一个值。

2.QueryDict.getlist(key, default=None)

?
1
返回带有请求键的数据列表。如果键不存在且 default 是 None,则返回一个空列表。除非提供的默认值不是一个列表,否则返回一个列表。

下面是一段代码,展示了get和getlist的使用。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
>>> 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'

HttpResponse对象

Django会自动创建HttpRequest(wsgi或者asgi创建)对象, HttpResponse则是后端开发人员负责实例化、填充和返回。每一个视图函数都必须返回一个HttpResponse对象。

HttpResponse类位于django.http模块中。

HttpResponse对象用法

典型的用法是将页面的内容以字符串、字节字符串或 memoryview 的形式传递给 HttpResponse 构造函数。例如:

?
1
2
>>> from django.http import HttpResponse
>>> response = HttpResponse("Hello World!")

这样,在函数结束的时候return response前端就能拿到响应数据了。

但如果你想增量添加内容,你可以使用 response 作为一个类似文件的对象:

?
1
2
3
>>> 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来处理这些东西

** 告诉浏览器将响应作为文件附件处理 **

?
1
2
3
4
>>> response = HttpResponse(my_data, headers={
...     'Content-Type': 'application/vnd.ms-excel',
...     'Content-Disposition': 'attachment; filename="foo.xls"',
... })

Content-Disposition 头并没有什么 Django 特有的内容,但是很容易忘记语法,所以我们把它包含在这里。

HttpResponse对象属性

1.HttpResponse.charset

表示响应将被编码的字符集的字符串。如果在 HttpResponse 实例化时没有给出,将从 content_type 中提取,如果不成功,将使用 DEFAULT_CHARSET(如果没有设置,默认为utf-8)设置。

2.HttpResponse.status_code

HttpResponse对象的 HTTP 状态码。

除非 reason_phrase 被明确设置,否则在构造函数外修改 status_code 的值也会修改 reason_phrase 的值。

HttpResponse对象方法

1.HttpResponse.set_cookie(key, value='', max_age=None, expires=None, path='/', domain=None, secure=False, httponly=False, samesite=None)

设置一个 cookie。参数与 Python 标准库中的 Morsel cookie 对象相同。

max_age should be an integer number of seconds, or None (default) if the cookie should last only as long as the client's browser session. If expires is not specified, it will be calculated.

expires 应是格式为 “Wdy, DD-Mon-YY HH:MM:SS GMT” 的字符串,或者是 UTC 的 datetime.datetime 对象。如果 expires 是一个 datetime 对象,将计算 max_age。

max_age在不远的将来会取代expires。

如果你想设置一个跨域的 cookie,请使用 domain。例如,domain=“example.com” 将设置一个可被 www.example.com、blog.example.com 等域读取的 cookie。否则,一个 cookie 将只能被设置它的域读取。

如果你想让 cookie 只在使用 https 方案进行请求时才发送给服务器,请使用 secure=True。

如果你想防止客户端的 JavaScript 访问 cookie,请使用 httponly=True。

HttpOnly 是包含在 Set-Cookie HTTP 响应头中的一个标志。它是 RFC 6265 标准中 Cookie 的一部分,可以作为一种有用的方式来降低客户端脚本访问受保护 Cookie 数据的风险。

使用 samesite=‘Strict' 或 samesite=‘Lax' 来告诉浏览器在执行跨源请求时不要发送这个 cookie。SameSite 并不是所有浏览器都支持,所以它并不能替代 Django 的 CSRF 保护,而是一种深度防御措施。

使用 samesite='‘None' (字符串)来明确说明这个 cookie 会随着所有的同站和跨站请求而发送。

Changed in Django 3.1:

允许使用 samesite='None (字符串)。

2.HttpResponse.delete_cookie(key, path='/', domain=None, samesite=None)

删除给定键的 cookie。如果键不存在,则静默失败。

由于 cookie 的工作方式,path 和 domain 应该与你在 set_cookie() 中使用的值相同,否则 cookie 可能不会被删除。

HttpResponse子类

HttpResponse子类可以直接参考Django文档,对于现在而言,最常用的莫过于JsonResponse子类。在此,会专门介绍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() 调用,用于生成响应。可以用来指定编码。

参考资料

请求和响应

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注服务器之家的更多内容!

原文链接:https://zy010101.blog.csdn.net/article/details/121030001#t4