• 进入"运维那点事"后,希望您第一件事就是阅读“关于”栏目,仔细阅读“关于Ctrl+c问题”,不希望误会!

Django Request和Response对象

Python框架 彭东稳 7年前 (2017-10-21) 20887次浏览 已收录 0个评论

一、HttpRequest对象

当请求一个页面时,Django创建一个HttpRequest对象。该对象包含request的元数据,然后Django调用相应的view函数(HttpRequest对象自动传递给该view函数<作为第一个参数>),每一个view负责返回一个HttpResponse对象。就像下面这个hello()函数:

下面解释HttpRequest和HttpResponse对象的API(属性),就是包含当前请求URL的一些信息。

1. HttpRequest属性

HttpRequest.scheme

一个字符串,表示请求的方案(通常是http或https)。

HttpRequest.path

请求页面的全路径,不包括域名。例如”/hello/world”。

HttpRequest.body

一个字符串,表示原始HTTP请求的正文。它对于处理非HTML形式的数据非常有用:二进制图像、XML等。 如果要处理常规的表单数据,应该使用HttpRequest.POST,因为Django已经将这些POST数据处理成QueryDict,而不是在body中的一节字符串。

你也可以使用”类文件“形式的接口从HttpRequest中读取数据。

HttpRequest.content_type

一个字符串,根据content_type参数获取MIME类型,比如浏览器访问是text/html,API访问时application/json。开发时可以根据这个来判断是什么设备访问,然后返回不同的数据。

HttpRequest.encoding

一个字符串,表示提交的数据的编码方式(如果为None则表示使用DEFAULT_CHARSET设置)。这个属性是可写的,你可以修改它来修改访问表单数据使用的编码。接下来对属性的任何访问(例如从GET或POST中读取数据)将使用新的encoding值。如果你知道表单数据的编码不在DEFAULT_CHARSET中,则使用它。

HttpRequest.method

请求中使用的HTTP方法的字符串表示。全大写表示。例如:

HttpRequest.GET

包含所有HTTP GET参数的类字典对象,参见QueryDict文档。

HttpRequest.POST

包含所有HTTP POST参数的类字典对象。参见QueryDict文档。服务器收到空的POST请求的情况也是有可能发生的。也就是说,表单form通过HTTP POST方法提交请求,但是表单中可以没有数据。因此,不能使用语句if request.POST来判断是否使用HTTP POST方法;应该使用if request.method == “POST” (参见本表的method属性)。注意: POST不包括file-upload信息,参见FILES属性。

HttpRequest.COOKIES

包含所有cookies的标准Python字典对象,Keys和values都是字符串。

HttpRequest.session

一个既可读又可写的类似于字典的对象,表示当前的会话。只有当Django启用会话的支持时才可用。

HttpRequest.FILES

用来上传文件,包含所有上传文件的类字典对象,FILES中的每个Key都是<input type=”file” name=”” />标签中name属性的值。FILES中的每个value同时也是一个标准Python字典对象,包含下面三个Keys:

  • filename:上传文件名,用Python字符串表示。
  • content-type:上传文件的Content type。
  • content:上传文件的原始内容。

注意:只有在请求方法是POST,并且请求页面中<form>有enctype=”multipart/form-data”属性时FILES才拥有数据。否则,FILES是一个空字典,上次不会成功。

HttpRequest.META

元数据信息,一个标准的Python字典,包含所有的HTTP头部。具体的头部信息取决于客户端和服务器,下面是一些示例:

  • CONTENT_LENGTH —— 请求的正文的长度(是一个字符串)。
  • CONTENT_TYPE —— 请求的正文的MIME 类型。
  • HTTP_ACCEPT —— 响应可接收的Content-Type。
  • HTTP_ACCEPT_ENCODING —— 响应可接收的编码。
  • HTTP_ACCEPT_LANGUAGE —— 响应可接收的语言。
  • HTTP_HOST —— 客服端发送的HTTP Host头部。
  • HTTP_REFERER —— Referring页面。
  • HTTP_USER_AGENT —— 客户端的user-agent字符串。
  • QUERY_STRING —— 单个字符串形式的查询字符串(未解析过的形式)。
  • REMOTE_ADDR —— 客户端的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键。

HttpRequest.user

是一个django.contrib.auth.models.User对象,代表当前登录的用户。如果访问用户当前没有登录,user将被初始化为django.contrib.auth.models.AnonymousUser的实例。你可以通过user的is_authenticated()方法来辨别用户是否登录:

只有激活Django中的AuthenticationMiddleware时该属性才可用。

2. HttpRequest方法

HttpRequest.get_host()

根据从HTTP_X_FORWARDED_HOST(如果打开USE_X_FORWARDED_HOST)和HTTP_HOST 头部信息返回请求的原始主机。如果这两个头部没有提供相应的值,则使用SERVER_NAME和SERVER_PORT。

但当主机位于多个代理的后面,get_host()方法将会失败。有一个解决办法是使用中间件重写代理的头部。

HttpRequest.get_full_path()

返回path,如果可以将加上查询字符串。

例如:”/music/bands/the_beatles/?print=true”

HttpRequest.build_absolute_uri(location)

返回location的绝对URI。如果location没有提供,则设置为request.get_full_path()。

如果URI已经是一个绝对的URI,将不会修改。否则,使用请求中的服务器相关的变量构建绝对URI。例如:”http://example.com/music/bands/the_beatles/?print=true”。

HttpRequest.get_signed_cookie(key, default=RAISE_ERROR, salt=”, max_age=None)

返回签名过的Cookie对应的值,如果签名不再合法则返回django.core.signing.BadSignature。如果提供default参数,将不会引发异常并返回default的值。

可选参数salt可以用来对安全密钥强力攻击提供额外的保护。max_age参数用于检查Cookie对应的时间戳以确保Cookie的时间不会超过max_age秒。

更多信息参见密钥签名

HttpRequest.is_secure()

如果请求时是安全的,则返回True;即请求是通过HTTPS发起的。

HttpRequest.is_ajax()

如果请求是通过XMLHttpRequest发起的,则返回True,方法是检查HTTP_X_REQUESTED_WITH头部是否是字符串’XMLHttpRequest’。大部分现代的JavaScript库都会发送这个头部。如果你编写自己的XMLHttpRequest调用(在浏览器端),你必须手工设置这个值来让is_ajax() 可以工作。

如果一个响应需要根据请求是否是通过AJAX发起的,并且你正在使用某种形式的缓存例如Django的cache middleware, 你应该使用vary_on_headers(‘HTTP_X_REQUESTED_WITH’) 装饰你的视图以让响应能够正确地缓存。

二、QueryDict对象

HttpRequest对象中,属性GET和POST得到的都是django.http.QueryDict所创建的实例。这是一个django自定义的类似字典的类,用来处理同一个键带多个值的情况。

在Python原始的字典中,当一个键出现多个值的时候会发生冲突,只保留最后一个值。而在HTML表单中,通常会发生一个键有多个值的情况,例如<select multiple>(多选框)就是一个很常见情况。

Django提供了QueryDict API,可以用来测试这些方法,进入django shell环境即可:

下面我们来看这个类中有什么方法:

这是一个构造函数,其中query_string需要一个字符串,例如:

如果query_string没有传入,则获得一个空的对象。

你所遇到的QueryDict对象,特别是request.POST和request.GET得到的。如果你想自己实例化一个对象,可以传递mutable=True使你所实例化的对象可变。当然request.POST和request.GET是django创建的,也就是说除非改django源码,否则它们是不可变的。

对于设置的键和值,会从encoding转码成Unicode。也就是说,如果传入的字符串query_string是GBK或者是utf-8的编码,将会自动转码成Unicode,然后用做字典的键和值。如果encoding = None,也就是没有设定的话,将使用DEFAULT_CHARSET的值,默认为:’utf-8’。

QueryDict实现所有标准的字典方法,还包括一些特有的方法:

QueryDict.__getitem__(key)

返回给出的key的值。如果key具有多个值,__getitem__()返回最后(最新)的值。如果key不存在,则引发django.utils.datastructures.MultiValueDictKeyError。(它是Python标准KeyError的一个子类,所以你仍然可以坚持捕获KeyError。)

QueryDict.__setitem__(key, value)

设置给出的key的值为[value](一个Python列表,只有一个元素value)。注意:只有对象是可以改变的时候才能使用,例如通过.copy()方法创建的对象,或者设置为可变类型。

QueryDict.__contains__(key)

如果给出的key已经设置,则返回True。它让你可以做if “foo” in request.GET这样的操作。

QueryDict.get(key, default)

使用与上面__getitem__()相同的逻辑,但是当key不存在时返回一个默认值。

QueryDict.setdefault(key, default)

类似标准字典的setdefault()方法,只是它在内部使用的是__setitem__()。也就是说,当key已经存在时,返回其值,key不存在时,返回default,同时添加key和default到对象中。

QueryDict.update(other_dict)

接收一个QueryDict或标准字典。类似标准字典的update()方法,但是它附加到当前字典项的后面,而不是替换掉它们。

QueryDict.items()

类似标准字典的items()方法,返回一个迭代对象。但是它使用的是和__getitem__一样返回最新的值的逻辑。

QueryDict.lists()

类似QueryDict.iteritems(),返回一个包含键值对的元祖(key, value)迭代对象 ,value是一个包括所有key的值的列表。

QueryDict.values()

类似标准字典的values()方法,但是它使用的是和__getitem__一样返回最新的值的逻辑。也就是返回一个所有键对应的最新值的列表。

QueryDict.copy()

返回对象的副本,使用Python标准库中的copy.deepcopy()。此副本是可变的,即使原始对象是不可变的。

QueryDict.getlist(key, default)

以Python列表形式返回所请求的键的数据。如果键不存在并且没有提供默认值,则返回空列表。它保证返回的是某种类型的列表,除非默认值不是列表。

QueryDict.setlist(key, list_)

为给定的键设置list_(与__setitem__()不同),可以设置一个多元素的列表。

QueryDict.appendlist(key, item)

将项追加到内部与键相关联的列表中。

QueryDict.setlistdefault(key, default_list)

类似setdefault,除了它接受一个列表而不是单个值。

QueryDict.pop(key)

返回给定键的值的列表,并从字典中移除它们。如果键不存在,将引发KeyError。

QueryDict.popitem()

删除字典任意一个成员(因为没有顺序的概念),并返回二值元组,包含键和键的所有值的列表。在一个空的字典上调用时将引发KeyError。

QueryDict.dict()

返回QueryDict的dict表示形式。对于QueryDict中的每个(key, list)对 ,dict将有(key, item) 对,其中item是列表中的一个元素,使用与QueryDict.__getitem__()相同的逻辑,也就是最新的:

QueryDict.urlencode([safe])

从数据中返回查询字符串格式。

可选地,urlencode可以传递不需要编码的字符。(这意味着要进行url编码)

三、HttpResponse对象

对于HttpRequest对象来说,是由Django自动创建。但是,HttpResponse对象就必须我们自己创建。每个View方法必须返回一个HttpResponse对象。

HttpResponse类在django.http.HttpResponse。

1. HttpResponse构造

一般地, 你可以通过给HttpResponse的构造函数传递字符串表示的页面内容来构造HttpResponse对象:

但是如果想要增量添加内容, 你可以把response当作filelike对象使用:

也可以给HttpResponse传递一个iterator作为参数,而不用传递硬编码字符串。 如果你使用这种技术, 下面是需要注意的一些事项:

  • iterator应该返回字符串。
  • 如果HttpResponse使用iterator进行初始化,就不能把HttpResponse实例作为filelike 对象使用。这样做将会抛出异常。

最后,再说明一下,HttpResponse实现了write()方法, 可以在任何需要filelike对象的地方使用HttpResponse对象。

你可以使用字典语法添加,删除headers:

2. HttpResponse属性

  • HttpResponse.charset

表示将在其中对响应进行编码的字符集。如果在http实例化时没有给出,它将从content_type中提取,如果不成功,将使用DEFAULT_CHARSET设置。

  • HttpResponse.status_code

响应HTTP的状态代码。除非显式设置了reason_phrase,否则修改构造函数外部的status_code值也将修改reason_phrase的值。

  • HttpResponse.reason_phrase

响应HTTP的reason_phrase。它使用HTTP标准的默认原因短语。除非显式设置,否则reason_phrase是由status_code的值决定的。

  • HttpResponse.streaming

默认为False。因此属性存在,因此中间件可以以不同于常规响应的方式处理流响应。

  • HttpResponse.closed

如果响应已关闭,则为True。

3. HttpResponse方法

  • HttpResponse.__init__(content=”, content_type=None, status=200, reason=None, charset=None)

HttpResponse使用给定的页面内容和内容类型实例化一个对象。

content:应该是一个迭代器或一个字符串。如果它是一个迭代器,它应该返回字符串,并且这些字符串将被连接在一起以形成响应的内容。如果它不是迭代器或字符串,它将在访问时转换为字符串。

content_type:是可选地由字符集编码完成的MIME类型,并用于填充HTTP Content-Type标头。如果未指定,则由默认设置DEFAULT_CONTENT_TYPE和DEFAULT_CHARSET设置组成:“text / html; charset = utf-8“。

status:是个响应的HTTP状态码。

reason:是HTTP响应短语,如200状态码的短语是Ok,如果未提供,将使用默认短语。

charset:是响应将被编码的字符集。如果没有给出,它将被提取content_type,如果不成功,DEFAULT_CHARSET将使用该设置。

  • HttpResponse.set_cookie(key, value=”, max_age=None, expires=None, path=’/’, domain=None, secure=None, httponly=False)

设置cookie。

  • HttpResponse.set_signed_cookie(key, value, salt=”, max_age=None, expires=None, path=’/’, domain=None, secure=None, httponly=True)

设置带签名的cookie。

  • HttpResponse.delete_cookie(key, path=’/’, domain=None)

删除cookie。

  • HttpResponse.getvalue()

返回HttpResponse.content。

  • HttpResponse.__setitem__(header, value)

设置响应头属性。

  • HttpResponse.__delitem__(header)

删除响应头属性。

  • HttpResponse.__getitem__(header)

访问响应头属性。

  • HttpResponse.has_header(header)

检查是否存在响应头属性。

4. HttpResponse子类

Django包含很多HttpResponse子类,用来处理不同的HTTP响应类型,和HttpResponse一样,这些子类在django.http中。

  • HttpResponseRedirect

构造函数接受单个参数,重定向到的URL。可以是全URL (e.g., ‘http://search.yahoo.com/&#8217;)或者相对URL(e.g., ‘/search/’),注意:这将返回HTTP状态码302。

  • HttpResponsePermanentRedirect

同HttpResponseRedirect一样,但是返回永久重定向(HTTP状态码301)。

  • HttpResponseNotModified

构造函数不需要参数。使用此项可指定自用户上次请求以来页面未被修改。

  • HttpResponseBadRequest

返回400 status code。

  • HttpResponseNotFound

返回404 status code。

  • HttpResponseForbidden

返回403 status code。

  • HttpResponseNotAllowed

返回405 status code,它需要一个必须的参数:一个允许的方法的list (e.g., [‘GET’,’POST’])。

  • HttpResponseGone

返回410 status code。

  • HttpResponseServerError

返回500 status code。

当然,你也可以自己定义不包含在上表中的HttpResponse子类。

在Django中返回HTTP错误码是很容易的。上面介绍了HttpResponseNotFound,HttpResponseForbidden,HttpResponseServerError等一些子类。View方法中返回这些子类的实例就OK了,例如:

另外在Django中,默认提供了常见的错误处理方式,结合这些子类可以返回一些默认错误页面。 详见:Django自定义错误视图

四、JsonResponse对象

JsonResponse也是HttpResponse的子类,用于创建JSON编码响应的HttpResponse子类,用于生成一个Json格式而非html/xml的响应格式。

class JsonResponse(data, encoder=DjangoJSONEncoder, safe=True, json_dumps_params=None, **kwargs)

第一个参数,即数据,应该是一个字典实例。如果safe参数设置为False (请参见下文),它可以是任何JSON可序列化的对象。

其默认Content-Type headers设置为 “application/json”。

encoder参数默认为django.core.serializers.json.DjangoJSONEncoder编码器,将用于序列化数据。有关此序列化程序的更多详细信息, 请参见Django系列化。

safe的参数默认为True,如果设置为False,则可以为序列化传递任何对象 (否则只允许字典实例)。如果safe为true,并且将non-dict对象作为第一个参数传递,则将引发TypeError异常。

json_dumps_params参数的字典或关键字参数是要传递给json.dumps()调用,用于生成响应。

Serializing non-dictionary objects

Without passing safe=False, a TypeError will be raised。

官网文档:https://docs.djangoproject.com/en/1.11/ref/request-response/#django.http.HttpRequest


如果您觉得本站对你有帮助,那么可以支付宝扫码捐助以帮助本站更好地发展,在此谢过。
喜欢 (1)
[资助本站您就扫码 谢谢]
分享 (0)

您必须 登录 才能发表评论!