Django实现表单验证、CSRF、cookie和session、缓存、数据库多表操作(双下划綫)
通常验证用户输入是否合法的话,是前端js和后端共同验证的,这是因为前端js是可以被禁用的,假如被禁用了,那就没法用js实现验证合法与否了,也就是即使用户输入的不合法,但是也没提示,用户也不知道怎么输入就合法了。
所以下面会讲到在django后台实现验证是否合法并将错误提示显示给用户。
1.django实现form表单验证
使用django内置功能实现用户输入信息的验证
新建一个project,比如叫django1217;
新建一个app,python manage.py startapp app01
settings,py,
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app01',#注册了ap01
] 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',
] #设置静态资源路径
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR,'static'),
)
urls.py,
from app01 import views urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login/', views.login),
]
app01→views.py,
from django.shortcuts import render # Create your views here. from django import forms #定义各个输入框的规则,比如下面的不允许user和pwd为空
class LoginForm(forms.Form): #字段的值比如跟html中该标签的name值一样
#比如这里的user对应html里<input type="text" name="user" />中的name值。
user = forms.CharField(required=True)
pwd = forms.CharField(required=True) def login(request):
if request.method == 'POST':
# u = request.POST.get('user')
# p = request.POST.get('pwd')
# print(u,p)
obj = LoginForm(request.POST) #如果所有规则都满足,则ret为true,只要有一条不满足,ret就为false。
ret = obj.is_valid() #obj.clean()就是获取到的用户输入信息
if ret:
print(obj.clean())
else: #obj.errors,获取错误信息。
print(obj.errors)
return render(request,'login.html')
templates→login.html,
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<input type="text" name="user" />
</div> <div>
<input type="password" name="pwd" />
</div> <input type="button" value="login" onclick="OnSubmit()"/> <script src="/static/js/jquery-1.12.4.js" ></script>
<script> function OnSubmit(){
var info_dict = {};
$('input').each(function(){ #将name值作为键,value值作为值,加入到字典。
var v = $(this).val();
var n = $(this).attr('name');
info_dict[n] = v;
}); $.ajax({
url : '/login/',
type : 'POST',
data : info_dict ,
success:function(data){ },
error:function(data){ }
})
} </script>
</body>
</html>
如果用户名密码都为空时点登陆,则obj.errors信息见下:
<ul class="errorlist"><li>pwd<ul class="errorlist"><li>This field is required.</li></ul></li><li>user<ul class="errorlist"><li>This field is required.</li></ul></li></ul>
#提示用户名密码都是被要求的
如果用户名为空,密码不为空时点登陆,则obj.errors信息见下:
<ul class="errorlist"><li>user<ul class="errorlist"><li>This field is required.</li></ul></li></ul>
#提示用户名是被要求的
如果都不为空,则obj.clean()信息见下:
{'pwd': '', 'user': ''}
#都不为空,也就不报错了,直接获取到用户输入的内容。
可见,当验证不通过时,obj.errors会保存一段html代码,默认是保存为html代码,也可以保存为其他类型,
obj.errors.as_data()
obj.errors.as_json() #保存为json格式
obj.errors.as_ul() #默认的
obj.errors.as_text()
2.在上面代码的基础上进行功能扩展
login.html,
<script src="/static/js/jquery-1.12.4.js" ></script>
<script> function OnSubmit(){
$('.input-warning').remove();
var info_dict = {};
$('input').each(function(){
var v = $(this).val();
var n = $(this).attr('name');
info_dict[n] = v;
}); $.ajax({
url : '/login/',
type : 'POST',
data : info_dict ,
dataType : 'json',
success:function(data){ #如果返回真,就跳转;返回假,就在html页面提示报警信息。
if(data['status']) {
location.href = 'https://www.baidu.com'
}
else{
$.each(data.message,function(k,v){
error_message = v[0].message;
var tag = document.createElement('span');
tag.className = 'input-warning';
tag.innerText = error_message;
$('input[name="' + k + '"]').after(tag); })}
},
error:function(data){ }
})
} </script>
views.py,
from django.shortcuts import render
from django.shortcuts import HttpResponse # Create your views here. from django import forms class LoginForm(forms.Form):
user = forms.CharField(required=True)
pwd = forms.CharField(required=True)
import json
def login(request):
if request.method == 'POST':
result = {'status':False,'message':''}
obj = LoginForm(request.POST)
ret = obj.is_valid()
if ret:
result['status'] = True
result['message'] = json.loads(obj.errors.as_json())
else:
from django.forms.utils import ErrorDict #obj.errors.as_json()本身就是json格式,所以没法再json.dumps,所以必须先json.loads,然后return HttpResponse(json.dumps(result))才不会报错。
result['message'] = json.loads(obj.errors.as_json()) return HttpResponse(json.dumps(result)) return render(request,'login.html')
3.在上面的基础上继续扩展
上面的提示信息都是英文的,下面演示如何自定义,
login.html新加两个input,
<div>
<input type="text" name="number" />
</div>
<div>
<input type="text" name="phone" />
</div>
views.py修改如下,
from django import forms
import re
from django.core.exceptions import ValidationError #自定义一个校验用户输入是否合法的函数
def mobile_validate(value):
mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
if not mobile_re.match(value):
raise ValidationError('手机号码格式错误') #“required=True”是默认就存在的,写不写都行;
#validators,使用自定义的函数来校验是否合法。
class LoginForm(forms.Form):
user = forms.CharField(required=True,error_messages={'required':'用户名不能为空'})
pwd = forms.CharField(min_length=6,max_length=15,error_messages={'required':'不能为空','min_length':'最小长度是6','max_length':'最大长度是15'})
number = forms.IntegerField(error_messages={'invalid':'必须是数字','required':'不能为空'})
phone = forms.CharField(validators=[mobile_validate, ],
error_messages={'required': u'手机不能为空'},)
4.使用html的form表单实现提交、使用django自动生成html标签
之所讲用ajax实现表单提交,有个很重要的因素是让用户输入的内容能保留;如果用form提交的话,会强制页面刷新,用户输入的东西会丢掉。下面讲解用form提交实现内容保留。
views.py,
from django.shortcuts import render
from django.shortcuts import HttpResponse # Create your views here. from django import forms
import re
from django.core.exceptions import ValidationError def mobile_validate(value):
mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
if not mobile_re.match(value):
raise ValidationError('手机号码格式错误') class LoginForm(forms.Form):
user = forms.CharField(required=True,error_messages={'required':'用户名不能为空'})
pwd = forms.CharField(min_length=6,max_length=15,error_messages={'required':'不能为空','min_length':'最小长度是6','max_length':'最大长度是15'})
number = forms.IntegerField(error_messages={'invalid':'必须是数字','required':'不能为空'})
phone = forms.CharField(validators=[mobile_validate, ],
error_messages={'required': u'手机不能为空'},) import json
def login(request):
if request.method == 'POST':
objPost = LoginForm(request.POST) #如果是POST方法,此时的objPost里的输入框其实是有用户输入的数据的,所以将objPost返回时,也就将用户的输入信息一并返回了。
return render(request,'login.html',{'obj':objPost}) else:
objGet = LoginForm() #如果是get方法,则直接将页面返回,也就是说所有的输入框都是空白的。
return render(request,'login.html',{'obj':objGet})
login.html,
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.input-warning{
color: #dc44cb;
}
</style>
</head>
<body>
<form action='/login/' method="post">
<div>
#引用一个obj.user,django就会在html里自动创建一个input标签
{{ obj.user }}
#如果有错误信息,才添加span标签并显示警告
{% if obj.errors.user %}
<span class="input-warning">{{ obj.errors.user.0 }}</span>
{% endif %}
</div> <div>
{{ obj.pwd }}
{% if obj.errors.pwd %}
<span class="input-warning">{{ obj.errors.pwd.0 }}</span>
{% endif %}
</div> <div>
{{ obj.number }}
{% if obj.errors.number %}
<span class="input-warning">{{ obj.errors.number.0 }}</span>
{% endif %}
</div>
<div>
{{ obj.phone }}
{% if obj.errors.phone %}
<span class="input-warning">{{ obj.errors.phone.0 }}</span>
{% endif %}
</div> <input type="submit" value="login"/> </form> </body>
</html>
注意,django版本不同,默认创建的标签可能不一样。比如number = forms.IntegerField(),在django1.9里自动生成一个和input框一模一样的框,在django1.10里会生成一个针对数字的框,这样的,
CharField()默认生成input标签,生成什么标签是可以指定的,也可以添加class、value等参数,见下,
#生成一个文本框标签,添加一个class和一个kkk3属性。
test = forms.CharField(widge=forms.Textarea(attrs={'class':'input-warning','kkk3':'iamgood'})) #生成一个select标签
select_choices = (
(0,'上海'),
(1,'北京'),
)
test = forms.CharField(widge=forms.Select(choices=select_choices))
5.CSRF介绍和使用
csrf是跨站域名伪造的缩写,如果django的settings.py里开启了这个,则form表单提交或ajax提交时必须携带着token(一段字符串,就当是密钥吧),否则会返回403拒绝错误。
django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成。而对于django中设置防跨站请求伪造功能有分为全局和局部。
全局:
中间件 django.middleware.csrf.CsrfViewMiddleware
局部:
- @csrf_protect,为当前函数(views.py里)强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
- @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
注:from django.views.decorators.csrf import csrf_exempt,csrf_protect
5.1 form表单提交配置csrf措施
urls.py,
url(r'^csrf/', views.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',
]
csrf.html,
<body>
<form action="/csrf/" method="post">
{% csrf_token %}#加上这一行,就能使csrf不拒绝了。
<input type="text" name="user" />
<input type="password" name="pwd" />
<input type="submit" value="submit"/>
</form>
</body>
views.py,
def csrf(request):
return render(request,'csrf.html')
5.2 ajax提交配置csrf措施
csrf.html,
<body>
<input type="button" onclick="Do();" value="Do it"/> <script src="/static/js/jquery-1.12.4.js"></script>
<script src="/static/js/jquery.cookie.js"></script>
<script type="text/javascript">
var csrftoken = $.cookie('csrftoken'); function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
} #一个html页面可能有多个ajax请求,比如有登录的有注册的,下面这几行代码的作用就是给每个ajax请求都绑定了csrf功能,不然的话,需要在每个ajax请求里单独配置csrf功能。
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
function Do(){ $.ajax({
url:"/csrf/",
data:{id:1},
type:'POST',
success:function(data){
console.log(data);
}
}); }
</script>
</body>
6.Cookie和Session介绍
Cookie保存在客户端的某个文件夹内;Session保存在服务端的数据库、memcached或/dev/shm等设备中。cookie是一个单独存在的东西,session依赖cookie。
用户进入网站登录后,浏览器会在本地写一个标识(可以是一个代号或者是一串字符串),下次用户再访问网站时,如果cookie里有内容并内容与session里的该用户的内容对应上了,这个用户就是登录状态了。
6.1 返回页面的同时往客户端写入cookie
def cookie(request):
obj = render(request,'cookie.html') #k1=v1
obj.set_cookie('k1','v1')
return obj
按照上面的代码,所有访问服务端的客户端都会写上一个k1、v1的cookie。
set_cookie函数:
def set_cookie(self,key,value='',max_age=None,expires=None,path='/',domain=None,secure=False,httponly=False): #key,键
#value,值
#max_age,这个cookie存活多少秒
#expires,指定一个过期时间
#path,‘/’这个表示cookie全域名有效。'/dotest'这个表示该cookie只在/dotest域名下有效,访问别的域名的话取不到这个cookie。
#domain=None,表示不允许跨域名有效,比如jd.com下的cookie不能用在taobao.com里。
#secure和httponly都是安全设置,但是设置了也不是百分百安全。
常用的就是key,value,max_age,expires,path。
cookie一般保存一些不敏感的信息,比如临时购物车商品、用户选择的一些属性(最大显示多少条信息,50条还是100条)。
像用户登录验证的信息,一般是服务端发给客户端一段随机码,cookie只保存这段随机码,下次访问网站的时候,把这随机码发给服务端(客户端不需要配置什么,浏览器会自动把cookie发给服务端),然后服务端拿这个随机码与sesion比对,如果对应上就允许访问内容,如果对应不上就跳转到登录界面。
验证的小例子:
def index(request):
username = request.COOKIES.get('username')
if username:
return render(request,'index.html',{'username':username})
else:
#如果在cookie里取不到用户名,就跳转到登录。
return redirect('/login/')
7. Session介绍以及使用
flask、tornado默认都没有提供session功能,要么用cookie实现验证,要么自己写一个session验证;django默认就提供session功能。
7.1 django实现session示例
urls.py,
url(r'^session_login/', views.session_login),
url(r'^session_index/', views.session_index),
session_index.html,
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>hi,{{ user }}welcome here.</h1>
</body>
</html>
session_login.html,
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<form action='/session_login/' method="post">
<div>
<input type="text" name="user"/>
</div>
<div>
<input type="password" name="pwd"/>
</div>
<input type="submit" value="login"/>
</form>
</body>
</html>
views.py,
def session_login(request):
if request.method == 'POST':
u = request.POST.get('user')
p = request.POST.get('pwd')
if u == 'z843248880' and p == '':
#如果用户名密码验证通过,这里做了两件事,第一,页面跳转到session_index;第二,保存session;request.session['user'] = u这一步就是django提供的session保存功能,它实际做了两件事,生成一个随机码放到本地,然后将这个随机码写入到浏览器的cookie里,下次浏览器访问会将cookie里的这个随机码发送给服务端比对。
request.session['user'] = u
return redirect('/session_index')
return render(request,'session_login.html') def session_index(request):
#获取session里的key是user的值
user = request.session.get('user',None)
if not user:
return redirect('/session_login/')
else:
return render(request,'session_index.html',{'user':user})
django的session可以保存在数据库、缓存、文件里,默认是保存在数据库的django_session表里,如果是新建的app,默认是没有表的,需要“python manage.py makemigrations;python manage.py migrate”生成默认表,这些表中就包含一个django_session表,这个表按如下的规则存储session:
session_id | value | expires |
l7ckctaz0omo4q3gpze4k5ob5f8eemud | user:z8432488880 | 两周(默认是两周的过期时间) |
7.2 创建验证session的装饰器
上面的代码,
def session_index(request):
user = request.session.get('user',None)
if not user:
return redirect('/session_login/')
else:
return render(request,'session_index.html',{'user':user})
可见,如果所有的页面都需要做session验证,则每个函数里都需要做一个“if not user”的判断,所以我们把验证的这个功能放到装饰器里,代码见下,
def auth(func):
def inner(request,*args,**kwargs):
user = request.session.get('user',None)
if not user:
return redirect('/session_login/')
return func(request,*args,**kwargs)
return inner @auth
def session_index(request):
user = request.session.get('user')
return render(request,'session_index.html',{'user':user})
7.3 添加注销功能
注销其实就是删除用户的session,然后跳转到登录页。用户的session保存在数据库里,只要删除这个用户的session即可,代码见下,
views.py,
@auth
def session_logout(request): #删除session
del request.session['user']
return redirect('/session_login/')
session_index.html,
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>hi,{{ user }}welcome here.</h1>
<a href="/session_logout">logout</a>
</body>
</html>
8.Session更多配置
django仅支持memcache作为缓存,如果要用redis,需要装第三方插件。
Django中默认支持Session,其内部提供了5种类型的Session供开发者使用:
- 数据库(默认)
- 缓存
- 文件
- 缓存+数据库
- 加密cookie
8.1 数据库Session
Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。 a. 配置 settings.py SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默认) 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过期(默认)
SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认) b. 使用(不论以什么方式保存session,“使用”都是没有区别的,也就是即使更换了存session的方法,也不用改业务代码,只需要改一下配置就行了) def index(request):
# 获取、设置、删除Session中数据
request.session['k1'] #获取
request.session.get('k1',None) #获取
request.session['k1'] = 123 #设置
request.session.setdefault('k1',123) # 如果k1有值则不设置
del request.session['k1'] #删除 # 所有 键、值、键值对
request.session.keys()
request.session.values()
request.session.items()
request.session.iterkeys()
request.session.itervalues()
request.session.iteritems() # 用户session的随机字符串
request.session.session_key # 将所有Session失效日期小于当前日期的数据删除
request.session.clear_expired() # 检查 用户session的随机字符串 在数据库中是否
request.session.exists("session_key") # 删除当前用户的所有Session数据
request.session.delete("session_key")
8.2 缓存session
a. 配置 settings.py SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎
SESSION_CACHE_ALIAS = 'default' # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存(下面有讲到缓存)的设置 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过期
SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存 b. 使用 同数据库session
比如使用Memcache缓存(python-memcached模块)作为缓存,则settings.py如下配置:
SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎
SESSION_CACHE_ALIAS = 'default' # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置 # 此缓存使用python-memcached模块连接memcache;下面三个CACHES选择其一 CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
}
} 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',
'172.19.26.242:11211',
]
}
} 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过期
SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存
8.3 文件session
a. 配置 settings.py SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 引擎
SESSION_FILE_PATH = None # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir() # 如:/var/folders/d3/j9tj0gz93dg06bmwxmhh6_xm0000gn/T 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过期
SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存 b. 使用 同数据库session
8.4 缓存加数据库session
数据库用于做持久化,缓存用于提高效率;如果缓存有就走缓存,缓存没有就从数据库取数据,再将数据写到缓存。 a. 配置 settings.py SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 引擎
# 这里也需要配置缓存,比如用Memcache,就写上Memcache的缓存配置。 b. 使用 同上
8.5 加密session
a. 配置 settings.py SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # 引擎 b. 使用 同上
9.缓存
由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache中,5分钟内再有人来访问时,则不再去执行view中的操作,而是直接从内存或者Redis中之前缓存的内容拿到,并返回。
Django中提供了6种缓存方式:
- 开发调试
- 内存
- 文件
- 数据库
- Memcache缓存(python-memcached模块)
- Memcache缓存(pylibmc模块)
9.1 配置
9.1.1 开发调试
# 此为开始调试用,实际内部不做任何操作
# 配置:
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】)
}
} # 自定义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
9.1.2 内存
# 此缓存将内容保存至内存的变量中
# 配置:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': 'unique-snowflake',#'unique-snowflake'是一个名字,可以随便起,缓存放在内存里是以字典形式存在,这个名字就是字典的名字。
}
} # 注:其他配置同开发调试版本
9.1.3 文件
# 此缓存将内容保存至文件
# 配置: CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': '/var/tmp/django_cache',
}
}
# 注:其他配置同开发调试版本
9.1.4 数据库
# 此缓存将内容保存至数据库 # 配置:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
'LOCATION': 'my_cache_table', # 数据库表名
}
} # 注:执行创建表命令 python manage.py createcachetable,执行这条命令后,django就会再额外创建一张 'my_cache_table'的表用来放置缓存数据。
9.1.5 Memcache缓存(python-memcached模块)
# 此缓存使用python-memcached模块连接memcache CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
}
} CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': 'unix:/tmp/memcached.sock',
}
} CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': [
#配置多个memcache服务器,memcache天生支持集群
'172.19.26.240:11211',
'172.19.26.242:11211',
]
}
}
9.1.6 Memcache缓存(pylibmc模块)
# 此缓存使用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',
]
}
}
9.2 应用
9.2.1 全站使用
使用中间件,经过一系列的认证等操作,如果内容在缓存中存在,则使用FetchFromCacheMiddleware获取内容并返回给用户,当返回给用户之前,判断缓存中是否已经存在,如果不存在则UpdateCacheMiddleware会将缓存保存至缓存,从而实现全站缓存 MIDDLEWARE = [
'django.middleware.cache.UpdateCacheMiddleware',
# 其他中间件...
'django.middleware.cache.FetchFromCacheMiddleware',
]
#把django.middleware.cache.FetchFromCacheMiddleware放在最后的分析:
#用户来访问网站,应该是满足了所有中间件的规则后,才将缓存(FetchFromCacheMiddleware)返回给用户,而不是不经过任何中间件就直接拿到缓存数据,所以把FetchFromCacheMiddleware放在最后。 #django.middleware.cache.UpdateCacheMiddleware放在第一的分析:
#UpdateCacheMiddleware的作用是如果没有缓存,则将数据写入到缓存,所以应该是执行了所有中间件的process_response方法,然后再执行UpdateCacheMiddleware这个中间件,不然,比如把UpdateCacheMiddleware放在了中间,
#那缓存之后,又有中间件的process_response方法里执行了添加数据的操作,则新添加的数据就没在缓存里面。
CACHE_MIDDLEWARE_ALIAS = ""
CACHE_MIDDLEWARE_SECONDS = ""
CACHE_MIDDLEWARE_KEY_PREFIX = ""
9.2.2 单独视图(页面)缓存
方式一:
from django.views.decorators.cache import cache_page #60*15是超时时间,这个设置优先,单位是秒,60*15就是15分钟
@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)),
]
9.2.3 页面局部使用
a. 引入TemplateTag {% load cache %} b. 使用缓存 {% cache 5000 缓存key %}
缓存内容
{% endcache %}
页面局部使用示例:
{% load cache %}
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="shortcut icon" href="123.ico">
<title name="ssss">ooo</title>
<meta charset="UTF-8">
</head> <body>
<h1>{{ c }}</h1>#c是返回的实时time
<div style="border:1px solid red;height:100px;">
{% cache 5 缓存key %}
{{ c }} #这块被缓存住了,所以5秒之内时间值是不对的。
{% endcache %}
</div>
</body>
</html>
10. Model一对多操作补充(一)
model操作补充:
a.基本操作
b.进阶
c.双下划綫
__,比较大小与操作
__,可以跨表
10.1 all()、values('user')、value_list('user')分别存储的什么
#创建一个UserInfo表
class UserInfo(models.Model):
user = models.CharField(max_length=32)
pwd = models.CharField(max_length=32)
queryset = UserInfo.objects.all(),这条命令会获取该表的所有对象数据,赋值给queryset,
也就是说queryset里存储的是【UserInfo对象1,UserInfo对象2,UserInfo对象3,】
queryset = UserInfo.objects.all().values('user')
queryset里存储的是字典,【{'user':'zsc','user':'zsc1'}】
queryset = UserInfo.objects.all().value_list('user')
queryset里存储的是元组,直接存储的user的值,【('zsc'),('zsc1')】
10.2 直接用id设置外键
#创建一对多关系表 class UserType(models.Model):
caption = models.CharField(max_length=32)
#用户类型包括超级用户、普通用户、游客 class UserInfo(models.Model):
user = models.CharField(max_length=32)
pwd = models.CharField(max_length=32)
user_type = models.ForeignKey('UserType') 创建一条UserInfo记录:
方法一:
UserInfo.objects.create(user='zsc',pwd='zsv',user_type=UserType.objects.get(id=2));这样创建的话会操作两次数据库,效率低。
方法二:
UserInfo这个表有外键,所以这个表有一列数据是“user_type_id”,这个“user_type_id”就对应着UserType里的数据。
UserInfo.objects.create(user='zsc',pwd='zsv',user_type_id=2)
10.3 利用双下划线跨表查询数据
10.3.1 仅在filter里使用双下划綫
#创建一对多关系表 class UserType(models.Model):
caption = models.CharField(max_length=32)
#用户类型包括超级用户、普通用户、游客 class UserInfo(models.Model):
user = models.CharField(max_length=32)
pwd = models.CharField(max_length=32)
user_type = models.ForeignKey('UserType') #单表查询:UserInfo.objects.filter(user='zsc')
#联表查询:
现在要查询所有用户类型是“普通用户”的所有用户名和密码
方法一:
uid = UserType.models.get(caption='普通用户').id
UserInfo.objects.filter(user_type_id=uid)
#这样做可以,但还是进行了两次数据库操作。
方法二:
UserInfo.objects.filter(user_type__caption='普通用户')
#用双下划綫实现了跨表查询数据
10.3.2 在values里使用双下划线
queryset = UserInfo.objects.filter(user_type__caption='普通用户').values('user')
#结果是:【{'user':'zsc1'},{'user':'zsc2'}】 queryset = UserInfo.objects.filter(user_type__caption='普通用户').values('user','user_type__caption')
#结果是:【{'user':'zsc1','user_type__caption':'普通用户'},{'user':'zsc2','user_type__caption':'普通用户'}】,可见这样就直接把User_Type里的数据直接拿过来显示了。
10.3.3 使用双下划线实现三张及以上表的数据联合
#创建一对多关系表 class some(models.Model):
name = models.CharField(max_length=32)
class UserType(models.Model):
caption = models.CharField(max_length=32)
#用户类型包括超级用户、普通用户、游客
something = models.ForeignKey('some')
class UserInfo(models.Model):
user = models.CharField(max_length=32)
pwd = models.CharField(max_length=32)
user_type = models.ForeignKey('UserType') 现在要查询所有用户name是“旺旺”的所有用户名和密码,name字段在some表里。
UserInfo.objects.filter(user_type__something__name='旺旺')
Django实现表单验证、CSRF、cookie和session、缓存、数据库多表操作(双下划綫)的更多相关文章
- python_way day19 HTML-day5 (form表单验证,CSRF,cookie,session,缓存)
python-way day19 1. dJango的form表单验证 2.CSRF 跨站请求伪造 3.cookie,session 4.缓存 一,django表单验证功能 1.django验证基础: ...
- PHP / JavaScript / jQuery 表单验证与处理总结: 第①部分 PHP 表单验证与处理
PHP VERSION = 5.3.10 一.关于 $_REQUEST PHP 文档关于 $_REQUEST 的说明: 说明 默认情况下包含了 $_GET,$_POST 和 $_COOKIE 的数组. ...
- 【表单验证】基于jQuery的高度灵活的表单验证(无UI)
表单验证是前端开发过程中常见的一个需求,产品需求.业务逻辑的不同,表单验证的方式方法也有所区别.而最重要的是我们要清楚,表单验证的核心原则是--错误信息提示准确,并且尽可能少的打扰/干扰用户的输入和体 ...
- Element 表单验证,不清空数据,仅仅取消表单字段校验
重置表单 this.$refs['ageForm'].resetFields() // 表单重置 仅清空校验 this.$refs['ageForm'].clearValidate() // 清除验证
- python运维开发(十九)----Django后台表单验证、session、cookie、model操作
内容目录: Django后台表单验证 CSRF加密传输 session.cookie model数据库操作 Django后台Form表单验证 Django中Form一般有2种功能: 1.用于做用户提交 ...
- WCF服务实现客户端Cookie共享,表单验证的解决方案
基于前几篇的文章,如果理解了通道 拦截器 服务转发的概念,相信你肯定也能理解咋的玩了. 说白了就是创建客户端的拦截器: 实现接口:IClientMessageInspector. 里面的方法就是客户 ...
- 第三百一十一节,Django框架,Form表单验证
第三百一十一节,Django框架,Form表单验证 表单提交 html <!DOCTYPE html> <html lang="en"> <head& ...
- 九 Django框架,Form表单验证
表单提交 html <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...
- 前端编程提高之旅(十)----表单验证插件与cookie插件
实际项目开发中与用户交互的常见手法就是採用表单的形式.取得用户注冊.登录等信息.而当用户注冊或登录后又须要记住用户的登录状态.这就涉及到经常使用的两个操作:表单验证与cookie增删查找. ...
- Django---静态文件配置,post提交表单的csrf问题(日后细说),创建app子项目和分析其目录,ORM对象关系映射简介,Django操作orm(重点)
Django---静态文件配置,post提交表单的csrf问题(日后细说),创建app子项目和分析其目录,ORM对象关系映射简介,Django操作orm(重点) 一丶Django的静态文件配置 #we ...
随机推荐
- ActiveReports中如何使用Excel数据源
ActiveReports支持的数据源类型非常多,无论是常用的Oracle数据库.SQL Server.mySQL,还是开源的PostgreSQL,只要是具有ODBC驱动的数据库都可以正常使用,本文讲 ...
- SPSS数据分析—广义估计方程
广义线性模型虽然很大程度上拓展了线性模型的应用范围,但是其还是有一些限制条件的,比如因变量要求独立,如果碰到重复测 量数据这种因变量不独立的情况,广义线性模型就不再适用了,此时我们需要使用的是广义估计 ...
- 对HTML5校验 自定义验证信息
在HTML5中,表单可以定义一个属性required来触发默认的校验机制,比如: <input type="text" required /> 弹出的错误提示默认为英文 ...
- IOS开发常见错误整理
1.Cannot create an NSPersistentStoreCoordinator with a nil model 这是在执行到这段代码时引发的: - (void)viewDidLoad ...
- MVC5+EF6 入门完整教程十一:细说MVC中仓储模式的应用
摘要: 第一阶段1~10篇已经覆盖了MVC开发必要的基本知识. 第二阶段11-20篇将会侧重于专题的讲解,一篇文章解决一个实际问题. 根据园友的反馈, 本篇文章将会先对呼声最高的仓储模式进行讲解. 文 ...
- DEV控件中GridView中的复选框与CheckBox实现联动的全选功能
最初的界面图如图1-1(全选框ID: cb_checkall DEV控件名称:gcCon ): 要实现的功能如下图(1-2 1-3 1-4)及代码所示: 图1-2 图1-3 图1-4 O(∩_∩ ...
- 图片上传预览 (URL.createObjectURL)
知识预备:1. URL.createObjectURL() 静态方法会创建一个 DOMString,它的 URL 表示参数中的对象.这个 URL 的生命周期和创建它的窗口中的 document 绑定. ...
- js正则表达式大全(4)
正则表达式在javascript中的几个实例1(转) ! 去除字符串两端空格的处理 如果采用传统的方式,就要可能就要采用下面的方式了 //清除左边空格 function js_ltrim(destst ...
- 动态拼接linq 使用Expression构造动态linq语句
最近在做动态构造linq语句,从网上找了很多,大多数,都是基于一张表中的某一个字段,这样的结果,从网上可以搜到很多.但如果有外键表,需要动态构造外键表中的字段,那么问题来了,学挖掘机哪家强?哦,不是, ...
- 【Python⑥】python的缩进,条件判断和循环
缩进 Python的最大特色是用缩进来标明成块的代码. 这点和其他语言区别很明显,比如大家熟悉的C语言里: ) { num+=; flag-=; } 而在python中: if flag>= 0 ...