python上安装reuquest_Python自动化开发学习22-Django上

session

上节已经讲了使用Cookie来做用户认证,但是

Cookie的问题

缺点:敏感信息不适合放在cookie里,敏感信息只能放在服务器端

优势:把部分用户数据分散的存放在每个客户端,减轻服务端的压力

Cookie是保存在用户浏览器端的键值对,Session是保存在服务器端的键值对。

Session依赖Cookie,Cookie保存随机字符串,凭借这个随机字符串获取到服务器端Session里的内容。

用Session来优化用户登录:用户登录后,生成一个随机字符串,通过Cookie发送给客户端保存。服务器端维护一个字典,字典的key就是这个随机生成的字符串,字典的value是另外一个字典,在服务器端保存各种用户的敏感信息。

Django的sessiong默认是保存在数据库中的,所以要使用session需要先执行生成数据库的2条命令:

python manage.py makemigrations

python manage.py migrate

即使你没有写任何一张表,也会默认生成一些表,其中 django_session 表中就是存放session信息的。

操作

session里存放的就是键值对,所以操作起来也跟字典一样。随便写一个登录的页面,用下面的处理函数进行操作:

USER_INFO = {

'test': {'pass': "test123"},

'user': {'pass': "user123"},

}

def login(request):

if request.method == "GET":

return render(request, 'login.html')

elif request.method == 'POST':

user = request.POST.get('user')

pwd = request.POST.get('pwd')

user_obj = USER_INFO.get(user)

if user_obj and user_obj.get('pass') == pwd:

# 1.生成随机字符串

# 2.写到用户浏览器Cookie

# 3.把随机字符串作为key保存到session中

# 4.设置对应的value

# 理论上是要完成上面4个步骤

# 但是都封装好了,用的时候只需要1步,就能完成上面的操作,下面是设置session的值

request.session['username'] = user

request.session['is_login'] = True

return redirect('/welcome/')

else:

return render(request, 'login.html')

def welcome(request):

# 获取session的值

if request.session.get('is_login'):

return HttpResponse('Welcome %s' % request.session['username'])

else:

return HttpResponse('登录失败')

登录页面:

上面用到了设置数据的操作和获取数据的操作。其他的操作方法见下面整理的内容。

获取、设置、删除Session中数据:

request.session['k1'] :获取值,如果key不存在会报错

request.session.get('k1',None) :获取值,如果key不存在,在获取到默认值。默认值默认是None

request.session['k1'] = 123 :设置值

request.session.setdefault('k1',123) :设置默认值,就是如果这个key有值就不改变,没有值就设置为第二个参数的值

del request.session['k1'] :删除值

对所有键、值、键值对的操作:

request.session.keys()

request.session.values()

request.session.items()

request.session.iterkeys()

request.session.itervalues()

request.session.iteritems()

iterkeys 和 keys 的区别,iterkeys 返回一个迭代器,而 keys 返回一个列表。

其他:

request.session.session_key :获取当前用户的随机字符串。但是一般这个用不着,不过是可以获取到的

request.session.clear_expired() :将所有Session失效日期小于当前日期的数据删除。过期的session,数据库是没有自动清除的机制的。不过缓存系统是有的

request.session.exists("session_key") :检查作为参数的随机字符串在数据库中是否存在。一般也用不着,因为获取值的时候已经包含这个判断了,没有会返回None

request.session.delete("session_key") :删除参数的Session的所有数据

request.session.clear() :删除当前用户的所有Session数据。和delete方法比较,delete需要提供session_key。而clear方法会先去获取到当前用户的key,然后delete

request.session.set_expiry(value) :设置超时时间

如果value是个整数,session会在些秒数后失效。

如果value是个datatime或timedelta,session就会在这个时间后失效。

如果value是0,用户关闭浏览器session就会失效。

如果value是None,session会依赖全局session失效策略。

下面的内容在 Lib/site-packages/django/conf/global_settings.py 这个文件里,是默认配置。要修改的话,就在我们的 settings.py 里设置一个值:

############

# SESSIONS #

############

# Cache to store session data if using the cache session backend.

SESSION_CACHE_ALIAS = 'default'

# Cookie name. This can be whatever you want.

SESSION_COOKIE_NAME = 'sessionid' # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串

# Age of cookie, in seconds (default: 2 weeks).

SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2 # Session的cookie失效日期,这里默认的是2周

# A string like "example.com", or None for standard domain cookie.

SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名

# Whether the session cookie should be secure (https:// only).

SESSION_COOKIE_SECURE = False # 是否Session的cookie只支持http传输

# The path of the session cookie.

SESSION_COOKIE_PATH = '/' # Session的cookie保存的路径

# Whether to use the non-RFC standard httpOnly flag (IE, FF3+, others)

SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输

# Whether to save the session data on every request.

SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存

# Whether a user's session cookie expires when the Web browser is closed.

SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期

# The module to store session data

SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 默认引擎

# Directory to store session files if using the file session module. If None,

# the backend will use a sensible default.

SESSION_FILE_PATH = None # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址

# class to serialize session data

SESSION_SERIALIZER = 'django.contrib.sessions.serializers.JSONSerializer'

CSRF(跨站请求伪造)

客户端第一次发起GET请求后,不仅返回了页面,同时还会返回一串加密字符串。之后客户端再提交数据的时候,需要把之前收到的字符串一并提交,这样服务器端的CSRF就会对字符串进行验证,确认收到的数据是之前发起请求的客户端提交上来的。

无CSRF的隐患,如果没有CSRF,正常客户端提交数据是提交给当前访问的网站。但是也是可以提交到别的网站去的(你可以提交到任何地方)。虽然你可以提交过去,但是这种方式你没有目标网站给你的加密字符串的,所以开启CSRF之后,直接就把这部分请求拦截了。

开启CSRF

django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成。而对于django中设置防跨站请求伪造功能有分为全局和局部。

全局,settings.py 文件中的MIDDLEWARE(中间件)里,是一个列表,之前都是先把下面的这行注释掉的:

'django.middleware.csrf.CsrfViewMiddleware',

局部

导入模块:from django.views.decorators.csrf import csrf_exempt,csrf_protect

@csrf_protect :为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。

@csrf_exempt :取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。

CSRF Token相关装饰器在CBV只能加到dispatch方法上

关于dispatch方法,可以看讲CBV时记得笔记:https://blog.51cto.com/steed/2091163

这里要做的就是继承父类的dispatch方法,然后加上装饰器:

from django.views.decorators.csrf import csrf_exempt, csrf_protect

class HomeView(View):

@method_decorator(csrf_exempt)

def dispatch(self, request, *args, **kwargs):

return super(HomeView, self).dispatch(request, *args, **kwargs)

def get(self, request):

return render(request, "home.html")

def post(self, request):

print("Home View POST method...")

return redirect("/index/")

应用-Form方式提交

第一次请求获取到的字符串在哪里,如何在提交form表单的时候加上获取的字符串,从而通过CSRF的验证。做一个简单的登录页面,上节有,然后去 settings.py 文件里开启之前一直注释掉的CSRF,按下面的方式提交:

{# 加上下面的标签就可以了 #}

{% csrf_token %}

如果form不带 csrf_token ,那么会返回403错误。这里查看客户端form标签内的源码可以发现,系统帮我们生成了一个隐藏的input标签

应用-Ajax方式提交

使用Ajax方式提交,需要先获取到csrf的字符串,客户端收到服务器端的字符串后,是保存在cookie里的,所以可以到cookie里去获取到。提交的时候也要带上这个csrf字符串,加一条请求头: headers: {'X-CSRFtoken': csrftoken}, 。

注意:下面的例子里专门导入了一个 jquery.cookie.js 的库,支持 $.cookie 的方法。这是纯前端的做法,如果用模板语言,可以用 ‘{{ csrf_token }}' 直接拿到csrf的字符串。

在原来的页面里,添加Ajax请求的按钮,并且绑定事件。验证不通过重新加载页面,验证通过则用 location.href 页面跳转:

{% csrf_token %}

$(function () {

$('#btn').click(function () {

var csrftoken = $.cookie('csrftoken'); // cookie里可能没有把

var csrftoken = ‘{{ csrf_token }}'; // 模板语言里也可以直接拿到

var user = $("input[name='user']").val();

var pwd = $("input[name='pwd']").val();

$.ajax({

url: '/login/',

type: 'POST',

data: {'user': user, 'pwd': pwd, 'ajax': true},

// data: {'csrfmiddlewaretoken': '{{ csrf_token }}', 'user': user, 'pwd': pwd, 'ajax': true},

// 可以放在headers里,也可以放在data里

headers: {'X-CSRFtoken': csrftoken},

success: function (arg) {

if(arg === 'OK'){

location.href = '/welcome/'

}else{

location.reload()

}

}

})

})

})

处理函数也在原来的基础上添加。通过 is_ajax = request.POST.get('ajax') 判断是否是ajax提交的请求。最后在return的时候返回不同的结果,其他都不变:

def login(request):

if request.method == "GET":

return render(request, 'login.html')

elif request.method == 'POST':

user = request.POST.get('user')

pwd = request.POST.get('pwd')

is_ajax = request.POST.get('ajax')

user_obj = USER_INFO.get(user)

if user_obj and user_obj.get('pass') == pwd:

# 1.生成随机字符串

# 2.写到用户浏览器Cookie

# 3.把随机字符串作为key保存到session中

# 4.设置对应的value

# 但是只需要一步,就能完成上面的操作,下面是设置session的值

request.session['username'] = user

request.session['is_login'] = True

print(request.session)

return HttpResponse('OK') if is_ajax else redirect('/welcome/')

else:

print('error')

return HttpResponse('error') if is_ajax else render(request, 'login.html')

统一设置ajax的csrf,如果页面里有多个ajax请求,可以统一进行设置。再或者比如之前的练习,已经写好了不带csrf的ajax请求,现在也不要去里面改了,用下面的方法统一加上。就是在ajax发送前,设置请求头加上X-CSRFtoken这个key并且设置值:

$(function () {

$.ajaxSetup({

beforeSend: function (xhr, settings) {

// xhr 就是 XHLHttpRequest 是一个对象

xhr.setRequestHeader('X-CSRFtoken', $.cookie('csrftoken')) // 设置请求头

}

});

$('#btn').click(function () {

// var csrftoken = $.cookie('csrftoken');

var user = $("input[name='user']").val();

var pwd = $("input[name='pwd']").val();

$.ajax({

url: '/login/',

type: 'POST',

data: {'user': user, 'pwd': pwd, 'ajax': true},

// headers: {'X-CSRFtoken': csrftoken},

success: function (arg) {

if(arg === 'OK'){

location.href = '/welcome/'

}else{

location.reload()

}

}

})

})

})

上面的代码还要再优化一个,只有POST请求需要加csrf,GET请求是不需要加的。但是在上面的代码里所有的ajax请求的前面都会在请求头加上csrf,这里要再做个判断。除了POST和GET还有其他好几种请求,一起做判断:

function csrfSafeMethod(method) {

// 下面的这几类HTTP请求是不需要加CSRF验证的,这个是官网的一个例子的用法

return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));

}

$(function () {

$.ajaxSetup({

beforeSend: function (xhr, settings) {

// xhr 就是 XHLHttpRequest 是一个对象

// settings 里就是下面的$.ajax({})大括号里的内容,这里要获取type检查是否需要加csrf

if (!csrfSafeMethod(settings.type) && !this.crossDomain){

// 满足上面的条件才需要设置请求头

xhr.setRequestHeader('X-CSRFtoken', $.cookie('csrftoken')) // 设置请求头

}

}

});

$('#btn').click(function () {

// var csrftoken = $.cookie('csrftoken');

var user = $("input[name='user']").val();

var pwd = $("input[name='pwd']").val();

$.ajax({

url: '/login/',

type: 'POST',

data: {'user': user, 'pwd': pwd, 'ajax': true},

// headers: {'X-CSRFtoken': csrftoken},

success: function (arg) {

if(arg === 'OK'){

location.href = '/welcome/'

}else{

location.reload()

}

}

})

})

})

中间件

在settings.py文件里有一个列表,里面列个各种中间件,包括上面将过的csrf。下面是原始的settings.py文件里的中间件的内容:

MIDDLEWARE = [

'django.middleware.security.SecurityMiddleware',

'django.contrib.sessions.middleware.SessionMiddleware',

'django.middleware.common.CommonMiddleware',

'django.middleware.csrf.CsrfViewMiddleware',

'django.contrib.auth.middleware.AuthenticationMiddleware',

'django.contrib.messages.middleware.MessageMiddleware',

'django.middleware.clickjacking.XFrameOptionsMiddleware',

]

用户发起请求,到请求到达Views之前,首先要通过这写中间件。这些中间件就是一个类,经过就是要调用这些中间件类里的方法,process_request方法。请求的返回也要先通过这些中间件,调用process_response方法,然后再发送给用户。

其他名称在其他的Web框架里,也有中间件,但是名字可能叫做:管道(Pipeline),HttpHandler。

自定义中间件

先以csrf的中间件举例,代码中引用的字符串是:'django.middleware.csrf.CsrfViewMiddleware' 。这个就是路径和类名。

可以到python的模块中找到这个文件和类。在 \Lib\site-packages\django\middleware\csrf.py 这个文件里有一个类 class CsrfViewMiddleware(MiddlewareMixin): ,这个类里就有process_request方法和process_response方法。并且可以看到这个类是继承了MiddlewareMixin这个类的,查看这个父类,可以看到这个类里就是调用上面的2个方法。

要写自己的中间件,就是要定义一个类,继承MiddlewareMixin。并且在类里写上process_request方法和process_response方法。

在项目下创建Middle文件夹来存放自定义的中间件,创建m1.py文件:

from django.utils.deprecation import MiddlewareMixin

class Row1(MiddlewareMixin):

def process_request(self, request):

print('ROW1_reuquest')

def process_response(self, request, response):

print('ROW1_response')

return response

class Row2(MiddlewareMixin):

def process_request(self, request):

print('ROW2_reuquest')

def process_response(self, request, response):

print('ROW2_response')

return response

上面写了2个类,就是2个中间件了。然后去setting.py里注册一下你的中间件:

MIDDLEWARE = [

'django.middleware.security.SecurityMiddleware',

'django.contrib.sessions.middleware.SessionMiddleware',

'django.middleware.common.CommonMiddleware',

'django.middleware.csrf.CsrfViewMiddleware',

'django.contrib.auth.middleware.AuthenticationMiddleware',

'django.contrib.messages.middleware.MessageMiddleware',

'django.middleware.clickjacking.XFrameOptionsMiddleware',

'Middle.m1.Row1',

'Middle.m1.Row2',

]

现在再访问你之前的页面,就能看到中间件print的信息了,并且可以看到触发的顺序:

ROW1_reuquest

ROW2_reuquest

[11/Apr/2018 11:24:04] "GET /login/ HTTP/1.1" 200 492

ROW2_response

ROW1_response

先触发request方法,并且是写在前面的中间件先触发。然后再是收到GET请求。最后触发response方法。

中间件的应用场景:通过中间件可以对所有的请求做一个统一的操作,比如黑名单过滤。

中间件中可以定义以下方法:

process_request(self, request) :处理请求前最先处理

process_view(self, request, callback, callback_args, callback_kwargs) :在process_request全部执行之后执行,还是从上到下

process_template_response(self, request, response) :如果views返回对象中有render方法,则会执行

process_exception(self, request, exception) :当views里出现异常时触发。exception就是异常的信息

process_response(self, request, response) :返回结果后到客户端收到响应前处理

常用的就2个,其他了解一下

缓存

由于Django是动态网站,所以每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用缓存。缓存是将某个views的返回值保存至内存或者memcache中,5分钟内(默认设置)再有人来访问时,则不再去执行views中的函数,而是直接从内存或者Redis中之前缓存的内容拿到,并返回。

Django中提供了6种缓存方式:

开发调试

内存

文件

数据库

Memcache缓存(python-memcached模块)

Memcache缓存(pylibmc模块)

配置

开发调试以及默认配置

实际内部不做任何操作,就是调试用的。只有第一个引擎是必须要设置的,其他都有默认配置(上面也是照着默认设的),不写就是使用默认设置,或者写上你要修改的设置。其它缓存方式的配置也是一样的,就是把引擎换一下,再加一个 'LOCATION' 就是缓存存放的位置:

# 此为开始调试用,实际内部不做任何操作。

# 配置:

CACHES = {

'default': {

'BACKEND': 'django.core.cache.backends.dummy.DummyCache', # 引擎

'TIMEOUT': 300, # 缓存超时时间(默认300,None表示永不过期,0表示立即过期)

'OPTIONS': {

'MAX_ENTRIES': 300, # 最大缓存个数(默认300,就是5分钟)

'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认1/3)

},

'KEY_PREFIX': '', # 缓存key的前缀(默认空)

'VERSION': 1, # 缓存key的版本(默认1)

'KEY_FUNCTION': default_key_func # 生成key的函数(默认函数会生成为:【前缀:版本:key】)

}

}

默认的 'KEY_FUNCTION' 是在 Lib\site-packages\django\core\cache\backends\base.py 文件里的default_key_func函数,就是生成一个包含 key_prefix, version, key 这3个变量的字符串返回。这里可以用我们自己的写的函数生成自己想要的样式:

def default_key_func(key, key_prefix, version):

"""

Default function to generate keys.

Construct the key used by all other methods. By default, prepend

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)

内存

# 此缓存将内容保存至内存的变量中

# 配置:

CACHES = {

'default': {

'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',

'LOCATION': 'unique-snowflake', # 这个必须是全局唯一的变量名,实际就是在内存中维护一个字典,这个是变量名

}

}

文件

# 此缓存将内容保存至文件

# 配置:

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模块)

# 此缓存使用python-memcached模块连接memcache

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',

}

}

# 或者是使用分布式的memcache

CACHES = {

'default': {

'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',

'LOCATION': [

'172.19.26.240:11211',

'172.19.26.242:11211',

]

}

}

# 或者是使用分布式的memcache,还可以带权重(权重是memcache做的)

CACHES = {

'default': {

'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',

'LOCATION': [

('172.19.26.240:11211', 2),

('172.19.26.242:11211', 3),

]

}

}

Memcache缓存(pylibmc模块)

和上面差不多,只是用的是不同的python模块,所以引擎要变一下。

# 此缓存使用pylibmc模块连接memcache

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',

]

}

}

# 权重也是有的

应用

准备测试环境

使用文件的形式来测试,在项目下创建一个cache文件夹来存放缓存文件,配置如下:

CACHES = {

'default': {

'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',

'LOCATION': os.path.join(BASE_DIR, 'cache'), # 缓存文件的路径

}

}

然后写一个显示当前时间戳的处理函数:

def cache(request):

import time

ctime = time.time()

return render(request, 'cache.html', {'ctime': ctime})

页面只要把时间戳显示出来:

{{ ctime }}

{{ ctime }}

现在访问页面会看到一个时间戳,并且刷新页面时间戳也会刷新,说明没有走缓存。因为上面我们只是把缓存配置上了,还是还没应用上。

全站应用缓存

这个太粗糙了,下面有更加精细的设置。

要给所有的请求都应用上缓存,这个功能适合放在中间件里。中间件里需要写2个中间件

查缓存,收到用户请求先查找缓存,如果命中则直接返回缓存的内容。这个中间件要放在后面的位置,只有通过了一系列验证的中间件后才能给用户返回数据。

写缓存,返回给用户之前没有缓存的内容的同时,需要把这个内容写到缓存里去,那么下次就有缓存了。这个中间件要放在靠前的位置,通过了一系列其他中间件加工之后,把最终返回的内容缓存起来。

MIDDLEWARE = [

'django.middleware.cache.UpdateCacheMiddleware',

# 其他中间件...

'django.middleware.cache.FetchFromCacheMiddleware',

]

# 下面是中间件的设置,主要看超时时间

CACHE_MIDDLEWARE_ALIAS = default

CACHE_MIDDLEWARE_SECONDS = 600 # 中间件缓存的超时时间,默认600秒。

CACHE_MIDDLEWARE_KEY_PREFIX = ''

视图应用缓存1:处理函数前加装饰器

from django.views.decorators.cache import cache_page

@cache_page(10) # timeout必填,单位秒

def func(request):

pass

视图应用缓存2:修改urls.py的

from django.views.decorators.cache import cache_page

urlpatterns = [

path('admin/', admin.site.urls),

path('cache/', cache_page(5)(views.cache)),

]

局部视图缓存:

就是在模板语言里声明,页面里的哪些内容是要应用缓存的

{#要应用缓存,先load一下cache#}

{% load cache %}

{{ ctime }}

{#然后在需要应用缓存的内容的前后加上标签#}

{#下面的c1是自定义的key,这里缓存的值的key貌似无法根据配置自动生成#}

{% cache 5 c1 %}

{{ ctime }}

{% endcache %}

首先要load缓存,然后在要应用缓存的内容前后用标签包起来。这里需要定义timeout时间和key。

这个局部的应用场景还是很多的,只缓存页面中不会频繁发生变化的内容,而经常会变的内容则不缓存

补充

在后面的模块写项目的时候遇到了,补充进来:

在后台调试缓存

测试临时存储的有失效性的 key 和 value。下面的例子中,在缓存里存了一个值,时间是5秒。有效时间内通过key可以获取到值,超过了之后,返回就是None。

G:\>python manage.py shell

Python 3.6.3 (v3.6.3:2c5fed8, Oct 3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)] on win32

Type "help", "copyright", "credits" or "license" for more information.

(InteractiveConsole)

>>> from django.core.cache import cache

>>> cache.set('k1', 'v1', 5)

>>> cache.get('k1')

'v1'

>>> cache.get('k1')

>>>

超时时间的小结

在CACHES里可以加上TIMEOUT设置超时时间,这个是引擎的超时时间。要使用缓存首先要设置一个引擎。

设置完引擎后,就是要应用缓存了。上面介绍了不同颗粒度的应用方式:中间件(全局)、url、视图函数、局部视图。每次应用的时候是没有选择引擎的,所以貌似引擎只能用CACHES设置好的那一个。但是每个方法都有自己的方式来设置超时时间。

关于超时时间的优先级,最后使用前测试一下。下面是猜测不是结论,url、视图函数、局部视图的优先级应该高于引擎的。中间件和引擎的超时设置都在配置文件里,具体是什么情况最好是测试一下。

信号

Django中提供了“信号调度”,用于在框架执行操作时解耦。通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒一些接受者。

Django内置信号

Model signals

pre_init : django的modal执行其构造方法前,自动触发

post_init : django的modal执行其构造方法后,自动触发

pre_save : django的modal对象保存前,自动触发

post_save : django的modal对象保存后,自动触发

pre_delete : django的modal对象删除前,自动触发

post_delete : django的modal对象删除后,自动触发

m2m_changed : django的modal中使用m2m字段操作第三张表(add,remove,clear)前后,自动触发

class_prepared : 程序启动时,检测已注册的app中modal类,对于每一个类,自动触发

Management signals

pre_migrate : 执行migrate命令前,自动触发

post_migrate : 执行migrate命令后,自动触发

Request/response signals

request_started : 请求到来前,自动触发

request_finished : 请求结束后,自动触发

got_request_exception : 请求异常后,自动触发

Test signals

setting_changed : 使用test测试修改配置文件时,自动触发

template_rendered : 使用test测试渲染模板时,自动触发

Database Wrappers

connection_created : 创建数据库连接时,自动触发

使用之前先要把对应的模块导入:

from django.db.models.signals import pre_init, post_init

from django.db.models.signals import pre_save, post_save

from django.db.models.signals import pre_delete, post_delete

from django.db.models.signals import m2m_changed

from django.db.models.signals import class_prepared

from django.db.models.signals import pre_migrate, post_migrate

from django.core.signals import request_started

from django.core.signals import request_finished

from django.core.signals import got_request_exception

from django.test.signals import setting_changed

from django.test.signals import template_rendered

from django.db.backends.signals import connection_created

注册函数1

将函数名作为参数完成注册

# 导入模块

from django.core.signals import request_started

# 准备好要触发的函数

def callback(sender, **kwargs):

print('callback')

print(sender, kwargs)

request_started.connect(callback) # 注册你的函数

# pre_init.connect(callback2) # 可以注册多个,先注册的先执行

注册函数2

为函数加上装饰器也能完成注册:

# 导入模块

from django.core.signals import request_started

from django.dispatch import receiver

# 准备好要触发的函数,并且加上装饰器

@receiver(request_started)

def callback(sender, **kwargs):

print('callback')

print(sender, kwargs)

自定义信号

要自定义信号需要3步:

定义信号 :这里单独创建一个文件(名字随意比如sg.py)来存放自定义的信号

注册信号 :定义完成好,直接就注册吧,注册方法和注册内置信号一样

触发信号 :在你要触发的位置,执行一个send()方法。比如下面的例子中是在处理函数中加入了这个信号的触发

内置信号只需要注册。而自定义的信号,需要在注册前先定义好这个信号。之后去你需要的位置加上触发信号的send()方法:

# sg.py 里的内容

# 第一步:定义信号

import django.dispatch

pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"]) # 这里要求2个参数

# 第二步:注册信号

def callback(sender, **kwargs):

print('callback')

print(sender, kwargs)

pizza_done.connect(callback)

# views.py 里的内容,当然可以是任何地方

# 第三步:触发信号

# 导入信号

from sg import pizza_done

def my_sig(request):

# 发送信号,第一个参数是发送者,后面是你自定义的函数要求的参数

pizza_done.send(sender='seven', topping=123, size=456)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值