通常验证用户输入是否合法的话,是前端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='旺旺')

最新文章

  1. git命令分类图
  2. ubuntu自动执行
  3. ubuntu 12.04 react-native 安装
  4. Flowplayer-Subtitle
  5. SharePoint 2013 开发——获取用户配置文件属性内容(User Profile)
  6. MySQL【Update误操作】回滚(转)
  7. Linux编译安装Darwin Streaming Server 6.0.3
  8. 从sample来学习Java堆(转)
  9. #WEB安全基础 : HTTP协议 | 0x11 HTTP的分块传输模块
  10. [20171115]ZEROCONF ROUTE.txt
  11. 以黄门镇黄湾村某一扶贫文档为例——将Excel数据填入到已存在的Word模板
  12. ubuntu16.04系统搜狗输入法的安装
  13. TOM带你玩充电 篇三:15款5号电池横评及选购建议——南孚金霸王小米宜家耐时品胜一个都逃不了
  14. fatal: incorrect checksum in control file
  15. FastCGI中fastcgi_param 详细说明
  16. 我的天$删除注册表$安装mysql最后一步不能启动服务的解决办法
  17. maven install时报错Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.12.4:test
  18. 7月12号day4总结
  19. POJ 3686 The Windy&#39;s(思维+费用流好题)
  20. 【Leetcode-easy】Palindrome Number

热门文章

  1. 解读浮动闭合最佳方案:clearfix
  2. SYSDBA身份登陆时可以修改其他用户的密码
  3. CSS3 HSL()详解:
  4. Java—数据库技术
  5. CentOS_7.2安装PHP_5.6
  6. C++11新特性学习
  7. 安装CAD2006装好了为什么不能用,显示系统错误无法启动此程序,因计算机丢失aclst.dll。尝试重新安装该程序以解
  8. js变量及其作用域
  9. bzoj 3530: [Sdoi2014]数数
  10. Android studio 提示:Can&#39;t use Subversion command line client: svn Probably the path to Subversion executable is wrong. Fix it.