Django框架【进阶篇】
第二十二章
内容:
session、form验证、中间件、缓存、信号
一.session
Django中默认支持Session,其内部提供了5种类型的Session供开发者使用:
- 数据库(默认)
- 缓存
- 文件
- 缓存+数据库
- 加密cookie
1、数据库Session
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。 2 3 a. 配置 settings.py 4 5 SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默认) 6 7 SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认) 8 SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认) 9 SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认) 10 SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认) 11 SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认) 12 SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认) 13 SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认) 14 SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认) 15 16 17 18 b. 使用 19 20 def index(request): 21 # 获取、设置、删除Session中数据 22 request.session['k1'] 23 request.session.get('k1',None) 24 request.session['k1'] = 123 25 request.session.setdefault('k1',123) # 存在则不设置 26 del request.session['k1'] 27 28 # 所有 键、值、键值对 29 request.session.keys() 30 request.session.values() 31 request.session.items() 32 request.session.iterkeys() 33 request.session.itervalues() 34 request.session.iteritems() 35 36 37 # 用户session的随机字符串 38 request.session.session_key 39 40 # 将所有Session失效日期小于当前日期的数据删除 41 request.session.clear_expired() 42 43 # 检查 用户session的随机字符串 在数据库中是否 44 request.session.exists("session_key") 45 46 # 删除当前用户的所有Session数据 47 request.session.delete("session_key") 48 49 request.session.set_expiry(value) 50 * 如果value是个整数,session会在些秒数后失效。 51 * 如果value是个datatime或timedelta,session就会在这个时间后失效。 52 * 如果value是0,用户关闭浏览器session就会失效。 53 * 如果value是None,session会依赖全局session失效策略。
2、缓存Session
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 a. 配置 settings.py 2 3 SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎 4 SESSION_CACHE_ALIAS = 'default' # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置 5 6 7 SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串 8 SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径 9 SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名 10 SESSION_COOKIE_SECURE = False # 是否Https传输cookie 11 SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输 12 SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周) 13 SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期 14 SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存 15 16 17 18 b. 使用 19 20 同上
3、文件Session
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 a. 配置 settings.py 2 3 SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 引擎 4 SESSION_FILE_PATH = None # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir() # 如:/var/folders/d3/j9tj0gz93dg06bmwxmhh6_xm0000gn/T 5 6 7 SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串 8 SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径 9 SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名 10 SESSION_COOKIE_SECURE = False # 是否Https传输cookie 11 SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输 12 SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周) 13 SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期 14 SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存 15 16 b. 使用 17 18 同上
4、缓存+数据库Session
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 数据库用于做持久化,缓存用于提高效率 2 3 a. 配置 settings.py 4 5 SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 引擎 6 7 b. 使用 8 9 同上
5、加密cookie Session
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 a. 配置 settings.py 2 3 SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # 引擎 4 5 b. 使用 6 7 同上
扩展:Session用户验证
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 def login(func): 2 def wrap(request, *args, **kwargs): 3 # 如果未登陆,跳转到指定页面 4 if request.path == '/test/': 5 return redirect('http://www.baidu.com') 6 return func(request, *args, **kwargs) 7 return wrap
二、form
django中的Form一般有两种功能:
- 输入html
- 验证用户输入
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import re 4 from django import forms 5 from django.core.exceptions import ValidationError 6 7 8 def mobile_validate(value): 9 mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$') 10 if not mobile_re.match(value): 11 raise ValidationError('手机号码格式错误') 12 13 14 class PublishForm(forms.Form): 15 16 user_type_choice = ( 17 (0, u'普通用户'), 18 (1, u'高级用户'), 19 ) 20 21 user_type = forms.IntegerField(widget=forms.widgets.Select(choices=user_type_choice, 22 attrs={'class': "form-control"})) 23 24 title = forms.CharField(max_length=20, 25 min_length=5, 26 error_messages={'required': u'标题不能为空', 27 'min_length': u'标题最少为5个字符', 28 'max_length': u'标题最多为20个字符'}, 29 widget=forms.TextInput(attrs={'class': "form-control", 30 'placeholder': u'标题5-20个字符'})) 31 32 memo = forms.CharField(required=False, 33 max_length=256, 34 widget=forms.widgets.Textarea(attrs={'class': "form-control no-radius", 'placeholder': u'详细描述', 'rows': 3})) 35 36 phone = forms.CharField(validators=[mobile_validate, ], 37 error_messages={'required': u'手机不能为空'}, 38 widget=forms.TextInput(attrs={'class': "form-control", 39 'placeholder': u'手机号码'})) 40 41 email = forms.EmailField(required=False, 42 error_messages={'required': u'邮箱不能为空','invalid': u'邮箱格式错误'}, 43 widget=forms.TextInput(attrs={'class': "form-control", 'placeholder': u'邮箱'})) 44 45 Form
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 def publish(request): 2 ret = {'status': False, 'data': '', 'error': '', 'summary': ''} 3 if request.method == 'POST': 4 request_form = PublishForm(request.POST) 5 if request_form.is_valid(): 6 request_dict = request_form.clean() 7 print request_dict 8 ret['status'] = True 9 else: 10 error_msg = request_form.errors.as_json() 11 ret['error'] = json.loads(error_msg) 12 return HttpResponse(json.dumps(ret)) 13 14 View
扩展:ModelForm
在使用Model和Form时,都需要对字段进行定义并指定类型,通过ModelForm则可以省去From中字段的定义
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class AdminModelForm(forms.ModelForm): 2 3 class Meta: 4 model = models.Admin 5 #fields = '__all__' 6 fields = ('username', 'email') 7 8 widgets = { 9 'email' : forms.PasswordInput(attrs={'class':"alex"}), 10 }
三、缓存
由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将 一个某个views的返回值保存至内存或者memcache中,5分钟内再有人来访问时,则不再去执行view中的操作,而是直接从内存或者Redis中 之前缓存的内容拿到,并返回。
Django中提供了6种缓存方式:
- 开发调试
- 内存
- 文件
- 数据库
- Memcache缓存(python-memcached模块)
- Memcache缓存(pylibmc模块)
1、配置
a、开发调试
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 # 此为开始调试用,实际内部不做任何操作 2 # 配置: 3 CACHES = { 4 'default': { 5 'BACKEND': 'django.core.cache.backends.dummy.DummyCache', # 引擎 6 'TIMEOUT': 300, # 缓存超时时间(默认300,None表示永不过期,0表示立即过期) 7 'OPTIONS':{ 8 'MAX_ENTRIES': 300, # 最大缓存个数(默认300) 9 'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3) 10 }, 11 'KEY_PREFIX': '', # 缓存key的前缀(默认空) 12 'VERSION': 1, # 缓存key的版本(默认1) 13 'KEY_FUNCTION' 函数名 # 生成key的函数(默认函数会生成为:【前缀:版本:key】) 14 } 15 } 16 17 18 # 自定义key 19 def default_key_func(key, key_prefix, version): 20 """ 21 Default function to generate keys. 22 23 Constructs the key used by all other methods. By default it prepends 24 the `key_prefix'. KEY_FUNCTION can be used to specify an alternate 25 function with custom key making behavior. 26 """ 27 return '%s:%s:%s' % (key_prefix, version, key) 28 29 def get_key_func(key_func): 30 """ 31 Function to decide which key function to use. 32 33 Defaults to ``default_key_func``. 34 """ 35 if key_func is not None: 36 if callable(key_func): 37 return key_func 38 else: 39 return import_string(key_func) 40 return default_key_func
b、内存
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 # 此缓存将内容保存至内存的变量中 2 # 配置: 3 CACHES = { 4 'default': { 5 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', 6 'LOCATION': 'unique-snowflake', 7 } 8 } 9 10 # 注:其他配置同开发调试版本
c、文件
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 # 此缓存将内容保存至文件 2 # 配置: 3 4 CACHES = { 5 'default': { 6 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', 7 'LOCATION': '/var/tmp/django_cache', 8 } 9 } 10 # 注:其他配置同开发调试版本
d、数据库
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 # 此缓存将内容保存至数据库 2 3 # 配置: 4 CACHES = { 5 'default': { 6 'BACKEND': 'django.core.cache.backends.db.DatabaseCache', 7 'LOCATION': 'my_cache_table', # 数据库表 8 } 9 } 10 11 # 注:执行创建表命令 python manage.py createcachetable
e、Memcache缓存(python-memcached模块)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 # 此缓存使用python-memcached模块连接memcache 2 3 CACHES = { 4 'default': { 5 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 6 'LOCATION': '127.0.0.1:11211', 7 } 8 } 9 10 CACHES = { 11 'default': { 12 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 13 'LOCATION': 'unix:/tmp/memcached.sock', 14 } 15 } 16 17 CACHES = { 18 'default': { 19 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 20 'LOCATION': [ 21 '172.19.26.240:11211', 22 '172.19.26.242:11211', 23 ] 24 } 25 }
f、Memcache缓存(pylibmc模块)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 # 此缓存使用pylibmc模块连接memcache 2 3 CACHES = { 4 'default': { 5 'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache', 6 'LOCATION': '127.0.0.1:11211', 7 } 8 } 9 10 CACHES = { 11 'default': { 12 'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache', 13 'LOCATION': '/tmp/memcached.sock', 14 } 15 } 16 17 CACHES = { 18 'default': { 19 'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache', 20 'LOCATION': [ 21 '172.19.26.240:11211', 22 '172.19.26.242:11211', 23 ] 24 } 25 }
2、应用
a. 全站使用
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 使用中间件,经过一系列的认证等操作,如果内容在缓存中存在,则使用FetchFromCacheMiddleware获取内容并返回给用户,当返回给用户之前,判断缓存中是否已经存在,如果不存在则UpdateCacheMiddleware会将缓存保存至缓存,从而实现全站缓存 2 3 MIDDLEWARE = [ 4 'django.middleware.cache.UpdateCacheMiddleware', 5 # 其他中间件... 6 'django.middleware.cache.FetchFromCacheMiddleware', 7 ] 8 9 CACHE_MIDDLEWARE_ALIAS = "" 10 CACHE_MIDDLEWARE_SECONDS = "" 11 CACHE_MIDDLEWARE_KEY_PREFIX = ""
b. 单独视图缓存
方式一: 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、局部视图使用
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 a. 引入TemplateTag 2 3 {% load cache %} 4 5 b. 使用缓存 6 7 {% cache 5000 缓存key %} 8 缓存内容 9 {% endcache %}
四、信号
Django中提供了“信号调度”,用于在框架执行操作时解耦。通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒一些接受者。
1、Django内置信号
1 Model signals 2 pre_init # django的modal执行其构造方法前,自动触发 3 post_init # django的modal执行其构造方法后,自动触发 4 pre_save # django的modal对象保存前,自动触发 5 post_save # django的modal对象保存后,自动触发 6 pre_delete # django的modal对象删除前,自动触发 7 post_delete # django的modal对象删除后,自动触发 8 m2m_changed # django的modal中使用m2m字段操作第三张表(add,remove,clear)前后,自动触发 9 class_prepared # 程序启动时,检测已注册的app中modal类,对于每一个类,自动触发 10 Management signals 11 pre_migrate # 执行migrate命令前,自动触发 12 post_migrate # 执行migrate命令后,自动触发 13 Request/response signals 14 request_started # 请求到来前,自动触发 15 request_finished # 请求结束后,自动触发 16 got_request_exception # 请求异常后,自动触发 17 Test signals 18 setting_changed # 使用test测试修改配置文件时,自动触发 19 template_rendered # 使用test测试渲染模板时,自动触发 20 Database Wrappers 21 connection_created # 创建数据库连接时,自动触发
对于Django内置的信号,仅需注册指定信号,当程序执行相应操作时,自动触发注册函数:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from django.core.signals import request_finished 2 from django.core.signals import request_started 3 from django.core.signals import got_request_exception 4 5 from django.db.models.signals import class_prepared 6 from django.db.models.signals import pre_init, post_init 7 from django.db.models.signals import pre_save, post_save 8 from django.db.models.signals import pre_delete, post_delete 9 from django.db.models.signals import m2m_changed 10 from django.db.models.signals import pre_migrate, post_migrate 11 12 from django.test.signals import setting_changed 13 from django.test.signals import template_rendered 14 15 from django.db.backends.signals import connection_created 16 17 18 def callback(sender, **kwargs): 19 print("xxoo_callback") 20 print(sender,kwargs) 21 22 xxoo.connect(callback) 23 # xxoo指上述导入的内容
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from django.core.signals import request_finished 2 from django.dispatch import receiver 3 4 @receiver(request_finished) 5 def my_callback(sender, **kwargs): 6 print("Request finished!")
2、自定义信号
a. 定义信号
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import django.dispatch 2 pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])
b. 注册信号
1 def callback(sender, **kwargs): 2 print("callback") 3 print(sender,kwargs) 4 5 pizza_done.connect(callback)
c. 触发信号
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from 路径 import pizza_done pizza_done.send(sender='seven',toppings=123, size=456)
由于内置信号的触发者已经集成到Django中,所以其会自动调用,而对于自定义信号则需要开发者在任意位置触发
上课笔记:
day22
知识点概要
- Session
- CSRF
- Model操作
- Form验证(ModelForm)
- 中间件
- 缓存
- 信号
内容详细:
1. Session
基于Cookie做用户验证时:敏感信息不适合放在cookie中
a. Session原理
Cookie是保存在用户浏览器端的键值对
Session是保存在服务器端的键值对
b. Cookie和Session对比
c. Session配置(缺少cache)
d. 示例:实现两周自动登陆
- request.session.set_expiry(60*10)
- SESSION_SAVE_EVERY_REQUEST = True
PS: cookie中不设置超时时间,则表示关闭浏览器自动清除
- session依赖于cookie
- 服务器session
request.session.get()
request.session[x] = x
request.session.clear()
- 配置文件中设置默认操作(通用配置):
SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认)
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认)
SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认)
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认)
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认)
# set_cookie('k',123)
SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认)
- 引擎的配置
2. CSRF
a. CSRF原理
b. 无CSRF时存在隐患
c. Form提交(CSRF)
d. Ajax提交(CSRF)
CSRF请求头 X-CSRFToken
6. 中间件
7. 缓存
5种配置
3种应用:
全局
视图函数
模板
8. 信号
- 内置信号
- 自定义
- 定义信号
- 出发信号
- 信号中注册函数
3. Model操作
a. 字段类型 + 参数
b. 连表字段 + 参数
c. Meta
d. SQL操作:
- 基本增删改查
- 进阶操作
- 正反查询
- 其他操作
e. 验证(弱)
4. Form操作
完成:
- 验证用户请求
- 生成HTML
(保留上一次提交的数据)
自定义:
- 类
- 字段(校验)
- 插件(生成HTML)
初始化操作:
a. Form验证用户请求
b. Form生成HTML
c. Form字段详细(自定义字段,Model...) + 插件
d. 自定义验证(钩子以及__all__)
e. 注册示例:
用户名、密码、邮箱、手机号(RegexValidator或RegexField)、性别、爱好、城市
f. 初始化值
5. ModelForm
a. Model+Form功能集合
b. save
c. save + save_m2m