Django之生命周期
前台发送URL请求到Django的中间件进行内容校验,完成校验后到达路由映射文件url.py,然后调用视图函数views.py里面的函数进行内容处理【 1.操作数据库进行数据读写 2. 调用前台的模版内容】最后返回字符串给前台进行页面的渲染【这里回去的时候也会经过中间件】。
Django之中间件
【更多参考】http://www.cnblogs.com/wupeiqi/articles/5246483.html
Django中间件类似于Java框架中的拦截器之类的东西,就是在请求到达我们要操作的函数之前添加的一些判断之类的操作。
应用场景: 适用于全局的操作,对所有的用户请求/用户返回数据都需要处理的情况。process_request适用于请求到达之前已经执行的操作,类似防护的操作[例如,csrf中间件,过滤器,自定义请求头];
Django中间件即类中的方法执行顺序是Django固定的,不能更改执行顺序,函数名称也不能更改【如果自定义了MiddlewareMixin的话,可以不使用固定的名称】
注:这里的函数是不需要全部写的,也就是process_request和process_response可有可无
中间件中可以定义四个方法,分别是:
process_request(self,request)
process_view(self, request, callback, callback_args, callback_kwargs)
process_template_response(self,request,response)
process_exception(self, request, exception)
process_response(self, request, response)
中间件实例
创建中间件路径【文件夹+文件】
settings.py
INSTALLED_APPS = [ ... 'app01', # 注册app ] STATICFILES_DIRS = (os.path.join(BASE_DIR, "statics"),) # 现添加的配置,这里是元组,注意逗号 TEMPLATES = [ ... 'DIRS': [os.path.join(BASE_DIR, 'templates')], ] MIDDLEWARE = [ ... # 'django.middleware.csrf.CsrfViewMiddleware', 'plugin.handler.Handler', 'plugin.handler.Handler2', 'plugin.handler.Handler3', ]
urls.py
from django.contrib import admin from django.urls import path from django.conf.urls import url, include from app01 import views urlpatterns = [ url('test/', views.Test), url('test/(d+)/', views.Test1), # url('test/(?P<nid>d{3})/', views.Test2), # 效果同Test1,只不过nid的名称是固定,kv形式返回 ]
views.py
from django.shortcuts import render, redirect, HttpResponse from app01 import models # 中间层操作 class Foo: def __init__(self, request, html): self.req = request self.html = html def render(self): return render(self.req, self.html) def Test(request): print('views') return HttpResponse("OK") def Test1(request,nid): print('views1') return HttpResponse("OK1") def Test2(request, nid): print('views2') return HttpResponse("OK2") # 测试process_template_response,这里不做细节演示 def Test4(request, nid): print('views2') return Foo(request, 'test.html')
plugin/handler.py
# version: python3.2.5 # 中间件测试 # 新的中间件【复制的原类,为了规范起见,所有中间件继承于此】 # 另:继承了自定义的MiddlewareClass就可以自定义函数名了,不一定是process_request class MiddlewareClass(object): def __init__(self, get_response=None): self.get_response = get_response super(MiddlewareClass, self).__init__() def __call__(self, request): response = None if hasattr(self, 'process_request'): # 执行当前中间件的process_request response = self.process_request(request) if not response: # 执行下一个中间件的__call__()方法 response = self.get_response(request) if hasattr(self, 'process_response'): # 执行当前中间件的process_response response = self.process_response(request, response) return response from django.utils.deprecation import MiddlewareMixin # 原始的继承类 from django.shortcuts import HttpResponse class Handler(MiddlewareClass): def process_request(self, request): print('A --> process_request') # return HttpResponse("Handler的process_response结束了请求...") #Django2.0.1中此方法会终止后面的中间件请求 # 根据url.py里面的路由映射获取views.py里面的函数,函数参数 # view_func: 函数名 # view_args:参数名 # view_kwargs: 如果参数名指定了列名,则key-value形式显示 # 执行的时候会按照A->B->C的顺序依次执行中间件内容,完成后去执行process_exception def process_view(self, request, view_func, view_args, view_kwargs): print('A --> process_view') # 这个函数只对views.py里面的报错进行处理,其他异常均不处理 # 异常处理完成后返回到最后一个中间件process_response进行response处理 def process_exception(self, request, exception): print('A --> process_exception') def process_response(self, request, response): print('A --> process_response') return response # views.py函数如果返回的是HttpResponse("OK1"),则这个函数并不做什么操作 # views.py函数如果返回的是Render(request, 'index.html'),则这个函数也不做什么操作 # views.py函数如果返回的对象new Obj()有Render方法,则这个函数会去render函数里面做操作 def process_template_response(self, request, response): print('A --> process_template_response') return response class Handler2(MiddlewareClass): def process_request(self, request): print('B --> process_request') def process_view(self, request, view_func, view_args, view_kwargs): print('B --> process_view') print('view_func:', view_func) print('view_args:', view_args) print('view_kwargs:', view_kwargs) def process_exception(self, request, exception): print('B --> process_exception') def process_response(self, request, response): print('B --> process_response') print("Response类型:", response) print("Response类型:", type(response)) return response def process_template_response(self, request, response): print('B --> process_template_response') return response class Handler3(MiddlewareClass): def process_request(self, request): print('C --> process_request') def process_view(self, request, view_func, view_args, view_kwargs): print('C --> process_view') def process_exception(self, request, exception): print('C --> process_exception') def process_response(self, request, response): print('C --> process_response') return response def process_template_response(self, request, response): print('C --> process_template_response') return response
templates/XXX.html
无
页面显示;
正常访问执行顺序:
中间件request请求中返回response效果:
另外其他的函数执行效果:
Django之CSRF[跨站请求伪造]
Django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成。而对于django中设置防跨站请求伪造功能有分为全局和局部。
全局:
中间件 django.middleware.csrf.CsrfViewMiddleware
局部:
@csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
@csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
注: from django.views.decorators.csrf import csrf_exempt,csrf_protect
settings.py里面如果未注释掉CSRF验证【即需要CSRF验证】
我们的get请求可以通过,post请求会被拦截
Django里面使用form的post请求发送数据的时候,一定是return了一个render对象,且HTML的form表单内使用了{% csrf_token %}进行标记,此时前台的HTML里面会多出一行csrf的token同时会缓存一份到Cookie里面。同理,如果我们需要ajax发送post请求的时候,是需要从Cookie里面获取token[从截图可以看到Cookie里面token的key是csrftoken]并添加到请求头[request-header]里让Django进行验证的。
Ajax请求CSRF实例
settings.py
INSTALLED_APPS = [ ... 'app01', # 注册app ] MIDDLEWARE = [ ... 'django.middleware.csrf.CsrfViewMiddleware', ... ] STATICFILES_DIRS = (os.path.join(BASE_DIR, "statics"),) # 现添加的配置,这里是元组,注意逗号 TEMPLATES = [ ... 'DIRS': [os.path.join(BASE_DIR, 'templates')], ]
urls.py
from django.contrib import admin from django.urls import path from django.conf.urls import url, include from app01 import views urlpatterns = [ url('login/', views.Login), ]
views.py
from django.shortcuts import render, redirect, HttpResponse from app01 import models # SCRF测试 def Login(request): # 注意这里的settings是Django默认的 # 我们看到的写入的settings.py文件会读入并覆盖conf里面的setting from django.conf import settings print('settings.CSRF_HEADER_NAME: ', settings.CSRF_HEADER_NAME) print(request.method) return render(request, 'login.html')
templates/login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> </head> <body> <form action="/login/" method="post"> {% csrf_token %} 姓名:<input type="text" name="username"> <input type="submit" value="Form提交"> <input type="button" value="Ajax提交" id="btn"> </form> </body> <script src="/static/jquery-2.1.4.min.js"></script> <script src="/static/JQuery.Cookies.js"></script> <script> $(function () { {# 这里对请求头做统一的处理,发送请求之前进行批量的配置 #} $.ajaxSetup({ beforeSend: function(xhr) { xhr.setRequestHeader("X-CSRFToken", $.cookie('csrftoken')); } }); $("#btn").click(function () { $.ajax({ url: '/login/', type:'POST', {# headers: {'X-CSRFTOKEN': 'hhh'},#} {# headers: {'X-CSRFTOKEN': $.cookie('csrftoken')}, 这里是自定义添加token#} data: {username: 'root'}, success: function (args) { console.log(args) } }) }) }) </script> </html>
PS: 获取request里面的请求信息,可以使用断点打印,我们可以看出我们request里的header经过Django处理后在Meta里面呢,且字段名前添加了HTTP的前缀。
页面显示;
其他
Django之缓存
【更多参考】http://www.cnblogs.com/wupeiqi/articles/5246483.html
由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache中,5分钟内再有人来访问时,则不再去执行view中的操作,而是直接从内存或者Redis中之前缓存的内容拿到,并返回。
缓存适用于固定内容且访问量大,大型文件内容,不具有实时性的内容。
缓存方式及配置
Django中提供了6种缓存方式:
开发调试 --> 什么都不干
内存
文件
数据库
Memcache缓存(python-memcached模块) -->在另外一台服务器上
Memcache缓存(pylibmc模块)
配置:
开发调试
# 此为开始调试用,实际内部不做任何操作 # 配置: CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.dummy.DummyCache', # 引擎 'TIMEOUT': 300, # 缓存超时时间(默认300,None表示永不过期,0表示立即过期) 'OPTIONS':{ 'MAX_ENTRIES': 300, # 最大缓存个数(默认300) 'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3) }, 'KEY_PREFIX': '', # 缓存key的前缀(默认空) 'VERSION': 1, # 缓存key的版本(默认1) 'KEY_FUNCTION' 函数名 # 生成key的函数(默认函数会生成为:【前缀:版本:key】) } } 注:memache帮我们生成key的时候,会以前缀+版本+key为默认key名称,具体看下面源码 # 自定义key def default_key_func(key, key_prefix, version): """ Default function to generate keys. Constructs the key used by all other methods. By default it prepends the `key_prefix'. KEY_FUNCTION can be used to specify an alternate function with custom key making behavior. """ return '%s:%s:%s' % (key_prefix, version, key) def get_key_func(key_func): """ Function to decide which key function to use. Defaults to ``default_key_func``. """ if key_func is not None: if callable(key_func): return key_func else: return import_string(key_func) return default_key_func
内存:
# 此缓存将内容保存至内存的变量中 # 配置: CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', 'LOCATION': 'unique-snowflake',# 此参数就是标志唯一变量名称用于指引value可任意指定 } } # 注:其他配置同开发调试版本
文件:
# 此缓存将内容保存至文件 # 配置: CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', 'LOCATION': '/var/tmp/django_cache', # 指定文件路径,文件存放位置 } } # 注:其他配置同开发调试版本
数据库:
# 此缓存将内容保存至数据库 # 配置: CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.db.DatabaseCache', 'LOCATION': 'my_cache_table', # 指定数据库表,一条数据就是一个缓存 } } # 注:执行创建表命令 python manage.py createcachetable -->专门防止缓存的表
Memcache缓存(python-memcached模块)
Memcache可以理解为另外一个服务器的内存,是内存级别的缓存;
内容以Key-Value形式存储,整体的Memcache就是一个大字典
# 此缓存使用python-memcached模块连接memcache # 3种连接方式 CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'LOCATION': '127.0.0.1:11211', # 根据IP和端口连接指定机器 } } # 此方法只能连接本机信息 CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'LOCATION': 'unix:/tmp/memcached.sock', # 以文件的形式连接[文件包含连接信息] } } CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'LOCATION': [ ('172.19.26.240:11211', 10), # 连接多个服务器,类似分布式哈~ ('172.19.26.242:11211', 15), # 数据存储再多个服务器上... ('172.19.26.241:11211,’ 20), # 设置了权重的连接,用户输入的key会计算hash值,返回一个int数字,后根据取余求算存储位置,根据权重确定服务器。加了权重后的,此时相当于10+15+20个服务器了,写入第三个服务器[有20个]的概率大 ] } }
Memcache缓存(pylibmc模块)
# 此缓存使用pylibmc模块连接memcache # 共3种连接方式 # 解释同上 CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache', 'LOCATION': '127.0.0.1:11211', } } CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache', 'LOCATION': '/tmp/memcached.sock', } } CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache', 'LOCATION': [ '172.19.26.240:11211', '172.19.26.242:11211', ] } }
注:memache中如果有服务器故障,因为memacahe里面没有检测机制,只能自己监控该模块,更改模块里面的接口方法处理
缓存应用
Django中提供了3种缓存方式:
全栈使用缓存
单独视图缓存
局部视图使用
A. 全栈使用的配置
settings.py
MIDDLEWARE = [ 'django.middleware.cache.UpdateCacheMiddleware', # 其他中间件... 'django.middleware.cache.FetchFromCacheMiddleware', ] CACHE_MIDDLEWARE_ALIAS = "" CACHE_MIDDLEWARE_SECONDS = "" CACHE_MIDDLEWARE_KEY_PREFIX = ""
B.单独视图缓存
settings.py
方式一: from django.views.decorators.cache import cache_page @cache_page(60 * 15) def my_view(request): ... 方式二: from django.views.decorators.cache import cache_page urlpatterns = [ url(r'^foo/([0-9]{1,2})/$', cache_page(60 * 15)(my_view)), ]
C.局部视图缓存
Html文件内写
a. 引入TemplateTag {% load cache %} b. 使用缓存 {% cache 5000 缓存key %} 缓存内容 {% endcache %}
单独视图和局部视图实例
settings.py
INSTALLED_APPS = [ ... 'app01', # 注册app ] MIDDLEWARE = [ ... # 'django.middleware.csrf.CsrfViewMiddleware', ... ] STATICFILES_DIRS = (os.path.join(BASE_DIR, "statics"),) # 现添加的配置,这里是元组,注意逗号 TEMPLATES = [ ... 'DIRS': [os.path.join(BASE_DIR, 'templates')], ] CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', 'LOCATION': os.path.join(BASE_DIR, 'cache'), # 指定文件路径,文件存放位置 } }
urls.py
from django.contrib import admin from django.urls import path from django.conf.urls import url, include from app01 import views urlpatterns = [ url('cache/', views.Cache), url('part/', views.Cache_part), ]
views.py
from django.shortcuts import render, redirect, HttpResponse from app01 import models # 文件缓存之单独视图[views]缓存 -->缓存整个页面及内容 from django.views.decorators.cache import cache_page @cache_page(10) def Cache(request): import time v = time.time() return HttpResponse(v) # 文件缓存之局部视图缓存 -->缓存部分页面内容 def Cache_part(request): import time v = time.time() return render(request, 'part.html', {'v':v})
templates/part.html
{% load cache %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> </head> <body> <h1>H1:{{ v }}</h1> {% cache 10 time %} <h5>H5: {{ v }}</h5> {% endcache %} </body> </html>
页面显示;
文件缓存之单独视图缓存 :
文件缓存之局部视图缓存 :
全栈使用实例
settings.py
INSTALLED_APPS = [ ... 'app01', # 注册app ] MIDDLEWARE = [ 'django.middleware.cache.UpdateCacheMiddleware', # 'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.cache.FetchFromCacheMiddleware', ] STATICFILES_DIRS = (os.path.join(BASE_DIR, "statics"),) # 现添加的配置,这里是元组,注意逗号 TEMPLATES = [ ... 'DIRS': [os.path.join(BASE_DIR, 'templates')], ] CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', 'LOCATION': os.path.join(BASE_DIR, 'cache'), # 指定文件路径,文件存放位置 } }
其余同部分的单独的使用...
页面显示;
全栈中间件代码分析:
from django.middleware.cache import FetchFromCacheMiddleware
from django.middleware.cache import UpdateCacheMiddleware
Django之bootStrap
bootStrap 一个集成css,js的文件
【bootStrap参考】 http://v3.bootcss.com/getting-started/