Django进阶
Form表单认证
作用:
- 验证用户提交的数据
- 生成HTML标签
在实际的生产环境中比如登录和验证的时候,我们一般都使用Jquery+ajax来判断用户的输入是否为空,假如JS被禁用的话,咱们这个认证屏障是不是就消失了呢?(虽然一般不会禁用掉但是还是存在风险)。所以我们一般做两种认证一种是前端做一遍认证,在后端做一遍认证。
#/usr/bin/env python
#-*- coding:utf-8 -*-
from django.shortcuts import render
# Create your views here.
def user_list(request):
host = request.POST.get('host')
port = request.POST.get('port')
mail = request.POST.get('mail')
mobile = request.POST.get('mobile')
#这里有个问题,如果,这个from表单有20个input,你在这里是不是的取20次?
#验证:
#输入不能为空,并且有的可以为空有的不可以为空
#如果email = 11123123 这样合法吗?
#如果mobile = 11123123 这样合法吗?
#如果ip = 11123123 这样合法吗?
'''
你在这里是不是需要做一大堆的输入验证啊?并且有很多这种页面会存在这种情况,如果每个函数都这样做估计就累死了
'''
return render(request,'user_list.html')
用form就可以解决这个问题,其他语言也叫作模型绑定。
from django import forms
import re
#自定义正则来增加判断规则
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(required=True,
min_length=6,
max_length=10,
error_messages={'required': '密码不能为空.', 'min_length': "至少6位"})
num = forms.IntegerField(error_messages={'required': '数字不能空.','invalid': '必须输入数字'})
#上面函数中的规则
phone = forms.CharField(validators=[mobile_validate, ],)
test_choices = (
(0, '上海'),
(1, '背景'),
)
test = forms.IntegerField(widget=forms.Select(choices=test_choices))
def login(request):
if request.POST:
objPost = LoginForm(request.POST)
ret = objPost.is_valid() #判断用户的输入是否合法
if ret:
print(objPost.clean())
else:
from django.forms.utils import ErrorDict
print('aaaaaaaaaaaaaaaaaaaa')
return render(request, 'login.html',{'obj1': objPost})
else:
objGet = LoginForm()
return render(request, 'login.html',{'obj1': objGet})
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style>
.error-msg{
color: red;
}
</style>
</head>
<body>
<form action="/login/" method="POST">
<div>
<div>
{{ obj1.user }}
{% if obj1.errors.user %}
<span class="error-msg">{{ obj1.errors.user.0 }}</span>
{% endif %}
</div>
<div>
{{ obj1.pwd }}
<span class="error-msg">{{ obj1.errors.pwd.0 }}</span>
</div>
<div>
{{ obj1.num }}
<span class="error-msg">{{ obj1.errors.num.0 }}</span>
</div>
<div>
{{ obj1.phone }}
<span class="error-msg">{{ obj1.errors.phone.0 }}</span>
</div>
<div>
{{ obj1.test }}
<span class="error-msg">{{ obj1.errors.test.0 }}</span>
</div>
<input type="submit" value="提交" />
</div>
</form>
</body>
</html>
效果:


跨站请求伪造
一、简介
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
二、应用
1、普通表单
2、Ajax
对于传统的form,可以通过表单的方式将token再次发送到服务端,而对于ajax的话,使用如下方式。
view.py
text.html
Session&Cookie
Cookie就是一段字符串,保存于本机电脑上。
session 保存于服务器,用来保存用户的会话信息,依赖于Cookies
1、流程
举个例子,咱们在登录一个网站后,拿JD举例,如果我登录进去之后,在想点击订单的时候。server断怎么判断我是“我”,而不是其他人呢?
Http是短连接,那么Server端肯定有一个保存我登录状态的地方(session),那server怎么判断是我发送过来的请求呢?就是通过Cookie!

当客户端访问过来后,server端会在IE里生成一个Cookie,当访问过来的时候就可以通过Cookie进行判断
2、结构
1、自动生成一段字符串
2、将字符串发送到客户端的浏览器,同时把字符串当做key放在session里。(可以理解为session就是一个字典)
3、在用户的session对应的value里设置任意值


3、操作
3.1、操作session
- 获取session:request.session[key]
- 设置session:reqeust.session[key] = value
- 删除session:del request[key]
request.session.set_expiry(value) * 如果value是个整数,session会在些秒数后失效。 * 如果value是个datatime或timedelta,session就会在这个时间后失效。 * 如果value是0,用户关闭浏览器session就会失效。 * 如果value是None,session会依赖全局session失效策略。
实例:
def login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if username == 'shuai' and password == '123':
result = request.session.get('IS_LOGIN', None)
print result
request.session['IS_LOGIN'] = True
return redirect('/index/')
obj = forms.LoginForm()
# 如果登录成功,写入session,跳转index
return render(request, 'account/login.html', {'model': obj})
def index(request):
'''
如果用户已经登录
'''
is_login = request.session.get('IS_LOGIN',False)
if is_login:
return render(request, 'home/index.html')
else:
return redirect('/login/')
注:这里需要注意在session中,我们可以设置多个key:value的值,方便我们做很多事情,比如判断哪个用户:
如果用户登录后,那么他肯定有一个cookie那么他在访问购物车的时候,怎么判断是哪个用户呢?我们可以在session设置,当用户登录的时候,我们把的用户名,增加到session中,那么用户携带cookie访问的时候,我们就能判断是哪个一用来访问的!
比如下面的对应关系:
user1
cookie :aaaa
server session(举例格式)
{session:aaaa{'IS_LOGIN':'True',username:'shuaige'}}
4、Session和Cookie好处
使用Session和Cookie的好处:Cookie可以理解为一个身份证ID,你只能拿着他去和Server端进行通信,如果你没有这个ID那么server端也不知道你是谁!
实例:(0 0 !)
我在写博客的时候在做Cookie和Session的实验,把Cookie删掉了!当我保存的时候直接给我提出来了,为什么呢?就是因为,server端不知道我是谁了,我已经没有密钥了。
所以,只要Session和Cookie任意一方失效,就可以理解为:
Cookie失效就相当于身份证ID过期,需要重新认证才可以继续使用。Session失效就相当于银行里的数据标识此ID无效,也需要重新申请。'
实例:
views.py
USER_LIST = ['abc','def']
def session_login(request):
if request.method == 'POST':
u = request.POST.get('user')
p = request.POST.get('pwd')
if p == '123' and u in USER_LIST:
request.session['user'] = u
return redirect('/session_index/')
return render(request,'session_login.html')
def session_index(request):
user = request.session.get('user',None)
return render(request,'session_index.html',{'user':user})
session_login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<form action="/session_login/" method="POST">
<input type="text" name="user">
<input type="text" name="pwd">
<input type="submit" value="提交" />
</form>
</body>
</html>
session_index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>欢迎:{{ user }}登录</h1>
<a href="/session_logout/">注销</a>
</body>
</html>
效果:


model操作
a. 基本操作
b. 进阶
c. 双下滑线
__ 大小于操作
__ 可以跨表
class UserInfo(models.Model):
user = models.CharField(max_length=32)
pwd = models.CharField(max_length=32)
queryset = UserInfo.objects.all()
【UserInfo对象,UserInfo对象,UserInfo对象,】
print(queryset.query) -- 查看UserInfo.objects.all() 的SQL语句
queryset = UserInfo.objects.all().values('user')
【{‘user’: 'alex'},{‘user’: 'eirc'}】
queryset = UserInfo.objects.all().value_list('user')
【('alex'),('eirc')】
=======================
一对多
class UserType(models.Model):
catption = models.CharField(max_length=32)
# 超级管理员,普通用户,游客,黑河
class UserInfo(models.Model):
user = models.CharField(max_length=32)
pwd = models.CharField(max_length=32)
user_type = models.ForignKey('UserType')
# user_type_id
# 创建UserInfo
1、 UserInfo.objects.create(user='alex',pwd='123',user_type=UserType.objects.get(id=2))
2、 UserInfo.objects.create(user='alex',pwd='123',user_type_id=2)
# 查询:
UserInfo.objects.filter(user='alex')
1、查询所有用户类型等于 普通用户 的所有用户名和密码
uid = UserType.objects.get(caption='普通用户').id
UserInfo.objects.filter(user_type_id=uid)
querset = UserInfo.objects.filter(user_type__caption='普通用户')
querset = UserInfo.objects.filter(user_type__id__gt=2)
【UserInfo对象,UserInfo对象,UserInfo对象,】
row = querset[0]
row.user
row.pwd
row.user_type.id
row.user_type.caption
###### objects __
###### row.外键字段.外键表的字段
querset = UserInfo.objects.filter(user_type__caption='普通用户').values('user','user_type__caption')
【{'user': 'alex','user_type__caption': '普通用户'},{'user': 'eric','user_type__caption': '普通用户'},】
row = querset[0]
row['user']
row['user_type__caption']
2、三张表跨表操作
class Somthing(models.Model):
name = models.CharField(max_length=32)
class UserType(models.Model):
catption = models.CharField(max_length=32)
s = models.ForignKey('Somthing')
# 超级管理员,普通用户,游客,黑河
class UserInfo(models.Model):
user = models.CharField(max_length=32)
pwd = models.CharField(max_length=32)
user_type = models.ForignKey('UserType')
UserInfo.objects.filter(user_type__s__name='xx')
model多对多操作
- 创建
a. 方式一:
class B2G(models.Model):
b_id = models.ForeignKey('Boy')
g_id = models.ForeignKey('Girl')
class Boy(models.Model):
username = models.CharField(max_length=16)
class Girl(models.Model):
name = models.CharField(max_length=16)
b. 方式二:
class Boy(models.Model):
username = models.CharField(max_length=16)
# girl_set
class Girl(models.Model):
name = models.CharField(max_length=16)
b = models.ManyToManyField('Boy')
- 操作:
添加:
正向
g1 = models.Girl.objects.get(id=1)
g1.b.add(models.Boy.objects.get(id=1))
g1.b.add(1)
bs = models.Boy.objects.all()
g1.b.add(*bs)
g1.b.add(*[1,2,3])
反向
b1 = models.Boy.objects.get(id=1)
b1.girl_set.add(1)
b1.girl_set.add(models.Girl.objects.all())
b1.girl_set.add(*[1,2,3,4])
...
删除:
g1 = models.Girl.objects.get(id=1)
g1.b.clear() # 清空和girl ID=1所关联的所有数据
g1.b.remove(2)
g1.b.remove(*[1,2])
查询:
g1 = models.Girl.objects.get(id=1) # SQL
g1.b.all() # SQL
g1.b.filter().count()
b1 = models.Boy.objects.get(id=1)
b1.girl_set.all()
models.Girl.objects.all().values('id','name', 'b__username')
models.Boy.objects.all().values('id','username', 'girl__name')
更新:
ORM:
python操作数据库模块:
MySQLdb
pymysql
原生SQL
# from django.db import connection
# cursor = connection.cursor()
# cursor.execute("""SELECT * from tb where name = %s""", ['Lennon'])
# row = cursor.fetchone()
model操作 F/Q
F:
temp = salary+500
models.UserInfo.objects.filter().update(salary=temp)
update userinfo set salary=salary+500
from django.db.models import F
models.UserInfo.objects.filter().update(salary=F('salary')+500)
Q:
构造搜索条件
1、传参
models.UserInfo.objects.filter(id=123,name='alex')
2、传字典
d = {'id': 123, 'name':'alex'}
models.UserInfo.objects.filter(**d)
<input name='id' />
<input name='name' />
获取用户输入,并构造成字典:
models.UserInfo.objects.filter(**c)
3、传Q对象
models.UserInfo.objects.filter(Q对象)
from django.db.models import Q
# q1 = Q()
# q1.connector = 'OR'
# q1.children.append(('id', 1))
# q1.children.append(('id', 2))
# q1.children.append(('id', 3))
# models.Tb1.objects.filter(q1)
# con = Q()
#
# q1 = Q()
# q1.connector = 'OR'
# q1.children.append(('id', 1))
# q1.children.append(('id', 2))
# q1.children.append(('id', 3))
#
# q2 = Q()
# q2.connector = 'OR'
# q2.children.append(('status', '在线'))
#
# con.add(q1, 'AND')
# con.add(q2, 'AND')
#
# models.Tb1.objects.filter(con)
实例:
models.py
from django.db import models
# Create your models here.
class UserType(models.Model):
caption = models.CharField(max_length=32)
views.py
from django.shortcuts import render,HttpResponse
# Create your views here.
from app01 import models
from django import forms
class indexForm(forms.Form):
c = models.UserType.objects.all().values_list('id','caption')
user_type_id = forms.IntegerField(widget=forms.Select(choices=c))
def __init__(self, *args, **kwargs):
super(indexForm, self).__init__(*args,**kwargs)
self.fields['user_type_id'].widget.choices = models.UserType.objects.all().values_list('id','caption')
def index(request):
# for i in range(10):
# models.UserType.objects.create(caption='CE' + str(i))
form = indexForm()
from django.db.models import Q
# q1 = Q()
# q1.connector = 'OR'
# q1.children.append(('id', 1))
# q1.children.append(('id', 2))
# q1.children.append(('id', 3))
# obj = models.UserType.objects.filter(q1)
# for item in obj:
# print(item.id,item.caption)
con = Q()
q1 = Q()
q1.connector = 'OR'
q1.children.append(('id', 1))
q1.children.append(('id', 2))
q1.children.append(('id', 3))
q2 = Q()
q2.connector = 'OR'
q2.children.append(('caption', 'CE1'))
q2.children.append(('caption', 'CE2'))
con.add(q1, 'AND')
con.add(q2, 'AND')
obj = models.UserType.objects.filter(con)
for item in obj:
print(item.id,item.caption)
return render(request, 'index.html',{'form':form})
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>ABC</h1>
{{ form }}
</body>
</html>
效果:

缓存
由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache中,5分钟内再有人来访问时,则不再去执行view中的操作,而是直接从内存或者Redis中之前缓存的内容拿到,并返回。
Django中提供了6种缓存方式:
- 开发调试
- 内存
- 文件
- 数据库
- Memcache缓存(python-memcached模块)
- Memcache缓存(pylibmc模块)
1、配置
a、开发调试
View Codeb、内存
View Codec、文件
View Coded、数据库
View Codee、Memcache缓存(python-memcached模块)
View Codef、Memcache缓存(pylibmc模块)
View Code2、应用
a. 全站使用
View Codeb. 单独视图缓存
View Codec、局部视图使用
View Code

浙公网安备 33010602011771号