Django使用非常熟练了,各种API接口不在话下,全都搞定。为方便定位问题在每个API接口的的开始和返回的地方都加上了log打印,记录入参和返回值。
但是这样有一个问题,需要每个API接口都要写一遍,非常的不Pythonic,有没有更好的方法呢?
如果大家对装饰器熟悉的话,会想到这个方法。写一个log_wrapper,在每个API的函数上写上@log_wrapper,这样看起来比较美观了。但是有一个问题,如果那个接口忘记使用这个装饰器了,日志就无法记录了。
在Django中有没有更好的解决方案呢,答案是肯定的。
2 Django HTTP处理流程 2.1 HTTP处理流程
我们先来熟悉下Django的HTTP处理流程,详细的处理流程请看下图。
每个HTTP请求过来,先经过request middleware处理,如果没有异常,则交由URLConf处理(即urls.py文件)来匹配URL,然后到view middleware处理,最后到具体的view业务函数。
HTTP请求中间处理的每个步骤,如果发生异常,直接返回response,而不是到下一个流程中。可以看到图中每个步骤都可以返回response。
2.2 Request和Response对象
在Django中,一个 HTTP 请求,首先被转化成一个 HttpRequest 对象,然后该对象被传递给 Request middleware处理,如果该middleware返回了Response,则生成一个Response对象,里面包含所有的HTTP 响应元素。
HttpRequest对象的属性
Attribute Description path 请求页面的全路径,不包括域名—例如, "/music/bands/the_beatles/"。 method 请求中使用的HTTP方法的字符串表示。全大写表示。例如: if request.method == 'GET': GET 包含所有HTTP GET参数的类字典对象。参见QueryDict 文档。 POST 包含所有HTTP POST参数的类字典对象。参见QueryDict 文档。 服务器收到空的POST请求的情况也是有可能发生的。也就是说,表单form通过HTTP POST方法提交请求,但是表单中可以没有数据。因此,不能使用语句if request.POST来判断是否使用HTTP POST方法;应该使用if request.method == "POST" (参见本表的method属性)。 注意: POST不包括file-upload信息。参见FILES属性。 REQUEST 为了方便,该属性是POST和GET属性的集合体,但是有特殊性,先查找POST属性,然后再查找GET属性。借鉴PHP’s $_REQUEST。 例如,如果GET =
{"name": "john"} 和POST =
{"age": '34'},则 REQUEST["name"] 的值是"john", REQUEST["age"]的值是"34". 强烈建议使用GET and
POST,因为这两个属性更加显式化,写出的代码也更易理解。 COOKIES 包含所有cookies的标准Python字典对象。Keys和values都是字符串。参见第12章,有关于cookies更详细的讲解。 FILES 包含所有上传文件的类字典对象。FILES中的每个Key都是<input
type="file" />标签中name属性的值. FILES中的每个value 同时也是一个标准Python字典对象,包含下面三个Keys: filename: 上传文件名,用Python字符串表示 content-type: 上传文件的Content type content: 上传文件的原始内容 注意:只有在请求方法是POST,并且请求页面中<form>有enctype="multipart/form-data"属性时FILES才拥有数据。否则,FILES 是一个空字典。 META 包含所有可用HTTP头部信息的字典。
例如: CONTENT_LENGTH CONTENT_TYPE QUERY_STRING: 未解析的原始查询字符串 REMOTE_ADDR: 客户端IP地址 REMOTE_HOST: 客户端主机名 SERVER_NAME: 服务器主机名 SERVER_PORT: 服务器端口 META 中这些头加上前缀HTTP_最为Key, 例如: HTTP_ACCEPT_ENCODING HTTP_ACCEPT_LANGUAGE HTTP_HOST: 客户发送的HTTP主机头信息 HTTP_REFERER:
referring页 HTTP_USER_AGENT:
客户端的user-agent字符串 HTTP_X_BENDER:
X-Bender头信息 user 是一个django.contrib.auth.models.User
对象,代表当前登录的用户。如果访问用户当前没有登录,user将被初始化为django.contrib.auth.models.AnonymousUser的实例。你可以通过user的is_authenticated()方法来辨别用户是否登录: if request.user.is_authenticated(): 只有激活Django中的AuthenticationMiddleware时该属性才可用 关于认证和用户的更详细讲解,参见第12章。 session 唯一可读写的属性,代表当前会话的字典对象。只有激活Django中的session支持时该属性才可用。 参见第12章。 raw_post_data 原始HTTP POST数据,未解析过。
高级处理时会有用处。
do_something()
elif request.method == 'POST':
do_something_else()
# Do something for logged-in users.
else:
# Do something for anonymous users.