Django的请求对象

【图书介绍】《Django 5企业级Web应用开发实战(视频教学版)》_django 5企业级web应用开发实战(视频教学版)-CSDN博客

《Django 5企业级Web应用开发实战(视频教学版)》(王金柱)【摘要 书评 试读】- 京东图书 (jd.com)

在Django框架中,HttpRequest对象是由HttpRequest类来定义的。HttpRequest对象是组成HTTP数据包的核心部件之一,其中包含了非常多的、十分重要的信息和数据。

每当一个客户端请求发送过来时,Django框架负责将HTTP数据包中的相关内容打包成为一个HttpRequest对象,并传递给相关视图函数作为第一位置参数(request)来调用。

HttpRequest类的属性有3类:由Django框架自身设置的属性、由应用代码设置的属性和由中间件设置的属性。

1. 由Django框架自身设置的属性

HttpRequest类的大部分属性均是只读(readonly)的,除非特别注明的属性。该类属性的详细内容介绍如下:

(1)HttpRequest.scheme:字符串类型,表示请求的协议种类,通常为“http”或“https”。

(2)HttpRequest.body:Bytes类型,表示原始HTTP请求的正文。该属性对于处理非HTML形式的数据(例如二进制图像、XML等)非常有用。注意,如果要处理常规的表单数据,应该使用下面将要介绍的HttpRequest.POST。

另外,还可以使用类似读写文件的方式从HttpRequest中读取数据,参见下面将要介绍的HttpRequest.read()。

(3)HttpRequest.path:字符串类型,表示当前请求页面的完整路径,但是不包括协议名和域名(例如“/article/authors/python/”)。

该属性非常有用,常用于在进行某项操作时,如果执行不通过就返回用户先前浏览的页面。

(4)HttpRequest.path_info:在某些Web服务器的配置中,主机名后的URL部分会被分成脚本前缀和路径信息这两个部分。path_info属性的作用是,不论使用的Web服务器是什么,该属性将始终包含路径信息部分。因此,使用该属性代替path可以保证代码在测试和开发环境中更容易地进行切换。

举例来讲,如果Web服务器配置中的WSGIScriptAlias参数设置为“/mydb”,那么当HttpRequest.path为“/article/authors/python/”时,HttpRequest.path_info则为“/mydb/article/authors/python/”。

(5)HttpRequest.method:字符串类型,表示请求使用的HTTP方法,默认为大写。具体使用方法如【代码4-55】所示。

【代码4-55】

01  if request.method == 'GET':
02      do_something()
03  elif request.method == 'POST':
04      do_something_else()

【代码分析】

通过HttpRequest对象的method属性判断请求的方法,然后根据请求方法的不同,在视图中执行不同的代码。

(6)HttpRequest.encoding:字符串类型,表示提交数据的编码方式(如果属性值为None,则表示使用DEFAULT_CHARSET设置)。

该属性是可写(编辑)的,可以通过修改该属性来改变表单数据的编码。另外,对于任何随后的属性访问(例如GET或POST),将会使用新的编码方式。

(7)HttpRequest.content_type:表示从CONTENT_TYPE头解析的请求的MIME类型。

(8)HttpRequest.content_params:包含在CONTENT_TYPE头标题中的键-值对参数字典。

(9)HttpRequest.GET:一个类似于字典的对象,包含GET请求中的所有参数。

举例来讲,在链接地址“http://example.com/?name=jack&age=18”中,“name=jack”和“age=18”就是字典对象类型的键-值对参数。

(10)HttpRequest.POST:包含所有POST表单数据的字典对象类型的键-值对参数。如果需要访问请求中的原始或非表单数据,可以使用HttpRequest.body属性。

注意,使用if条件语句通过判断“request.method=="POST"”来甄别一个请求是否为POST类型,而不要直接使用request.POST进行判断。

此外,POST中不包含上传的文件数据。

(11)HttpRequest.COOKIES:该属性包含所有Cookie信息的字典,键-值对均为字符串。可以使用类似字典类型的方式在Cookie中读写数据。注意,Cookie是不安全的,因此不要写敏感重要的信息。

(12)HttpRequest.FILES:该属性为一个类似于字典的对象,包含所有上传的文件数据。HttpRequest.FILES中的每个键为“<input type="file" name="" />”中的name属性值,对应的每个值为一个UploadedFile对象。

在Django框架中,实现文件上传功能主要依靠该属性。如果请求方式是POST且请求的<form>中带有“enctype="multipart/form-data"”属性,则HttpRequest.FILES属性将包含上传的文件数据;否则,HttpRequest.FILES将为一个空的类似于字典的对象,属于被忽略、无用的情形。

(13)HttpRequest.META:该属性为一个包含所有HTTP头部信息的字典。可用的头部信息取决于客户端和服务器,具体示例如下:

  • CONTENT_LENGTH:请求正文的长度(以字符串计)。
  • CONTENT_TYPE:请求正文的MIME类型。
  • HTTP_ACCEPT:可接收的响应Content-Type。
  • HTTP_ACCEPT_ENCODING:可接收的响应编码类型。
  • HTTP_ACCEPT_LANGUAGE:可接收的响应语言种类。
  • HTTP_HOST:客服端发送的HOST头部。
  • HTTP_REFERER:Referring页面。
  • HTTP_USER_AGENT:客户端的“user-agent”字符串。
  • QUERY_STRING:查询字符串。
  • REMOTE_ADDR:客户端的IP地址,可以获取客户端的IP信息。
  • REMOTE_HOST:客户端的主机名。
  • REMOTE_USER:服务器认证后的用户,前提是用户可用。
  • REQUEST_METHOD:表示请求方式的字符串,例如“GET”或“POST”。
  • SERVER_NAME:服务器的主机名。
  • SERVER_PORT:服务器的端口(字符串)。

 以上介绍的是比较重要和比较常用的头部信息,完整详细的信息请参考官方文档。

根据上述内容可知,除CONTENT_LENGTH和CONTENT_TYPE之外,请求中的任何HTTP头部键在转换为META键时,都会将所有字母转为大写并将连接符替换为下画线最后加上“HTTP_”前缀。因此,一个叫作X-Bender的头部将转换成META中的HTTP_X_BENDER键。

(14)HttpRequest.headers:该属性是一个不区分大小写的、类似dict的对象,包含请求中HTTP头部的所有信息。

(15)HttpRequest.resolver_match:该属性用于对请求中的URL地址进行解析,获取一些相关的信息(例如namespace等)。

在视图中通过request.resolver_match.namespace的方式来访问。

1)由应用代码设置的属性

这类属性不由Django框架自身进行设置,而使用应用代码进行设置。该类属性的详细内容介绍如下:

(1)HttpRequest.current_app:该属性表示当前应用(app)的名字。在url模板标签中,将使用该属性值作为reverse()方法的current_app参数。

(2)HttpRequest.urlconf:该属性设置当前请求的根URLconf模块,用于指定不同的URL路由入口,这将覆盖settings配置中ROOT_URLCONF参数的设置。将该属性值修改为None,将可恢复对ROOT_URLCONF参数的设置。

(3)HttpRequest.exception_reporter_filter:该属性用于替代当前请求中的DEFAULT_EXCEPTION_ REPORTER_FILTER。

(4)HttpRequest.exception_reporter_class:该属性用于替代当前请求中的DEFAULT_EXCEPTION_ REPORTER。

2)由中间件设置的属性

这类属性是在Django框架中由contrib应用中包含的一些中间件在请求上设置的。如果在请求中没有看到这些属性,那么需确认正确的中间件类名是否在MIDDLEWARE列表中。该类属性的详细内容介绍如下:

(1)HttpRequest.session:该属性来自SessionMiddleware中间件,是一个可读写的、类似字典的对象,表示当前会话。如果要保存用户状态、回话过程等,需要的就是这个中间件和这个属性。

(2)HttpRequest.site:该属性来自CurrentSiteMiddleware中间件,是get_current_site()方法返回的Site对象或RequestSite对象的实例,代表当前具体站点。

另外,Django框架是支持多站点的。如果同时上线了几个站点,就需要为每个站点设置一个站点id。

(3)HttpRequest.user:该属性来自AuthenticationMiddleware中间件,表示当前登录的用户的AUTH_USER_MODEL实例。该模型是Django框架内置的Auth模块下的User模型。如果用户当前未登录,则user将被设置为AnonymousUser对象的实例。

在实际应用中,可以通过is_authenticated方法判断当前用户是否为合法用户,示例代码如下:

【代码4-56】

01  if request.user.is_authenticated:
02      ... # 为已登录用户执行某些操作
03  else:
04      ... # 为匿名用户执行某些操作

【代码分析】

通过HttpRequest对象中user属性的is_authenticated方法判断当前用户是否为合法用户,然后根据登录用户或匿名用户在视图中执行不同的代码。

2. 方法

(1)HttpRequest.get_host()方法:该方法返回根据HTTP_X_FORWARDED_HOST(前提是被允许)和HTTP_HOST头部信息获取的请求的原始主机。如果这两个头部信息没有提供相应的值,则使用SERVER_NAME和SERVER_PORT头部信息。

举例来讲,当主机位于多个代理的后面时,get_host()方法将会失败。解决办法之一就是使用中间件重写代理的头部,示例代码如下:

【代码4-57】

01  class MultipleProxyMiddleware:
02      FORWARDED_FOR_FIELDS = [
03          'HTTP_X_FORWARDED_FOR',
04          'HTTP_X_FORWARDED_HOST',
05          'HTTP_X_FORWARDED_SERVER',
06      ]
07  
08      def __init__(self, get_response):
09          self.get_response = get_response
10  
11      def __call__(self, request):
12          """
13          Rewrites the proxy headers so that only the most
14          recent proxy is used.
15          """
16          for field in self.FORWARDED_FOR_FIELDS:
17              if field in request.META:
18                  if ',' in request.META[field]:
19                      parts = request.META[field].split(',')
20                      request.META[field] = parts[-1].strip()
21          return self.get_response(request)

【代码分析】

这段代码中定义的中间件MultipleProxyMiddleware,将在其他中间件(从get_host()方法的返回值中获取的,例如CommonMiddleware中间件或CsrfViewMiddleware中间件)之前被定位。

(2)HttpRequest.get_port()方法:该方法使用META中的HTTP_X_FORWARDED_PORT(前提是被允许)和SERVER_PORT的信息返回请求的始发端口。

(3)HttpRequest.get_full_path()方法:该方法返回包含完整参数列表的路径path,例如“/article/authors/python/?print=true”。

(4)HttpRequest.build_absolute_uri(location)方法:该方法返回location的绝对URI形式。如果location没有提供,则使用request.get_full_path()方法获取的值。例如“https://example.com/article/ authors/python/?print=true”。

 一般不建议在同一站点上混合部署HTTP和HTTPS,如果需要将用户重定向到HTTPS,最好使用Web服务器将所有HTTP流量重定向到HTTPS。

(5)HttpRequest.get_signed_cookie(key,default=RAISE_ERROR,salt='',max_age=None)方法:该方法从已签名的Cookie中获取值,如果签名不合法则返回django.core.signing.BadSignature对象。其中,可选参数salt用来为密码提供额外保护,从而提高安全系数;max_age参数用于检查Cookie对应的时间戳是否超时。官方文档给出的应用实例如下:

>>> request.get_signed_cookie('name')
'Tony'
>>> request.get_signed_cookie('name', salt='name-salt')
'Tony' # 假设使用相同的salt设置了Cookie
>>> request.get_signed_cookie('non-existing-cookie')
...
KeyError: 'non-existing-cookie'
>>> request.get_signed_cookie('non-existing-cookie', False)
False
>>> request.get_signed_cookie('cookie-that-was-tampered-with')
...
BadSignature: ...
>>> request.get_signed_cookie('name', max_age=60)
...
SignatureExpired: Signature age 1677.3839159 > 60 seconds
>>> request.get_signed_cookie('name', False, max_age=60)
False

(6)HttpRequest.is_secure()方法:如果使用的是HTTPS,则该方法返回True,表示链接是安全的。

(7)HttpRequest.accepts(mime_type)方法:如果请求头部接收的类型匹配mime_type参数,则该方法返回True,否则返回False。该方法是Django v3.1版本的新增功能。官方文档给出的应用实例如下:

>>> request.accepts('text/html')

True

(8)HttpRequest.read(size=None)方法、HttpRequest.readline()方法、HttpRequest.readlines()方法和HttpRequest.__iter__()方法:这4个方法都是从HttpRequest实例读取文件数据的方法,可以将HttpRequest实例直接传递到XML解析器。请看下面关于解析ElementTree(元素树)的代码实例。

【代码4-58】

01  import xml.etree.ElementTree as ET
02  for element in ET.iterparse(request):
03      process(element)

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值