Day19 Django之Form表单验证、CSRF、Cookie、Session和Model操作

时间:2021-08-14 22:31:54
Day19 Django之Form表单验证、CSRF、Cookie、Session和Model操作

一、Form表单验证

用于做用户提交数据的验证
1.自定义规则

a、自定义规则(类,字段名==html中的name值)
b、数据提交-规则进行匹配
代码如下:

"""day19_django URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/1.10/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.conf.urls import url, include
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from django.contrib import admin
from app01 import views urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login/', views.login),
]

urls.py

"""
Django settings for day19_django project. Generated by 'django-admin startproject' using Django 1.10.2. For more information on this file, see
https://docs.djangoproject.com/en/1.10/topics/settings/ For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.10/ref/settings/
""" import os # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'pv#lfw8ywtf=ws8mr%f9b)ihc0s@oj-2$wu^2o@)+(^)$i_9*n' # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True ALLOWED_HOSTS = [] # Application definition INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app01',
] 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',
] ROOT_URLCONF = 'day19_django.urls' TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')]
,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
] WSGI_APPLICATION = 'day19_django.wsgi.application' # Database
# https://docs.djangoproject.com/en/1.10/ref/settings/#databases DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
} # Password validation
# https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
] # Internationalization
# https://docs.djangoproject.com/en/1.10/topics/i18n/ LANGUAGE_CODE = 'en-us' TIME_ZONE = 'UTC' USE_I18N = True USE_L10N = True USE_TZ = True # Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.10/howto/static-files/ STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)

settings.py

from django.shortcuts import render,HttpResponse
from django import forms
from django.forms.utils import ErrorDict
import json
from django.core.exceptions import ValidationError
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=12,
error_messages={'required':'密码必须不能为空',
'min_length':'至少6位',
'max_length':'最多12位'})
num = forms.IntegerField(error_messages={'required':'数字不能为空', 'invalid':'必须输入数字'})
#url = forms.EmailField()
phone = forms.CharField(validators=[mobile_validate, ],) def login(request):
if request.method == 'POST':
result = {'status':False, 'message':None}
obj = LoginForm(request.POST)
ret = obj.is_valid()
if ret:
print(obj.clean())
result['status'] = True
else:
print(type(obj.errors), obj.errors.as_json())
error_str = obj.errors.as_json()
result['message'] = json.loads(error_str)
return HttpResponse(json.dumps(result))
return render(request, 'login.html')

views.py

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.error-msg{
background-color: red;
}
</style>
</head>
<body>
<div>
<div>
<input type="text" name="user" />
</div>
<div>
<input type="text" name="num" />
</div>
<div>
<input type="text" name="phone" />
</div>
<div>
<input type="password" name="pwd" />
</div>
<input type="button" value="提交" onclick="DoSubmit();" />
</div>
<script src="/static/jquery-1.12.4.js"></script>
<script>
function DoSubmit() {
var dict_input = {};
$('input').each(function () {
var v = $(this).val();
var n = $(this).attr('name');
dict_input[n] = v;
});
console.log(dict_input);
$('.error-msg').remove();
$.ajax({
url:'/login/',
type:'POST',
data:dict_input,
dataType: 'json',
success:function (result) {
if(result.status){
location.href = '/index/';
}else{
$.each(result.message, function (k, v) {
console.log(k, v[0].message);
//<sapn class="error-msg">错误信息</span>
var tag = document.createElement('span');
tag.className = 'error-msg';
tag.innerText = v[0].message;
//input[name="user"]
$('input[name="' + k + '"]').after(tag);
})
} },
error:function () { }
})
}
</script>
</body>
</html>

login.html

2.用于做用户提交数据的验证 + 生成HTML标签

代码如下:

from django.shortcuts import render,HttpResponse
from django import forms
from django.forms.utils import ErrorDict
import json
from django.core.exceptions import ValidationError
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=12,
error_messages={'required':'密码必须不能为空',
'min_length':'至少6位',
'max_length':'最多12位'})
num = forms.IntegerField(error_messages={'required':'数字不能为空', 'invalid':'必须输入数字'})
#url = forms.EmailField()
phone = forms.CharField(validators=[mobile_validate, ],)
#生成input标签,并加属性,设置样式
#test = forms.CharField(widget=forms.TextInput(attrs={'k1':'123','class':'error-msg'}))
#生成下拉列表,真正提交数据还是数字
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:
#obj1.errors是ErrorDict,ErrorDict继承dict
# for k,v in objPost.errors.items():
# print(k, v)
# print(objPost.errors['phone'][0])
# print(objPost.errors['user'][0])
# print(objPost.errors['num'][0])
pass
return render(request, 'login.html', {'obj1': objPost})
else:
objGet = LoginForm()
return render(request, 'login.html', {'obj1':objGet})

views.py

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.error-msg{
background-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 }}
{% if obj1.errors.pwd %}
<span class="error-msg">{{ obj1.errors.pwd.0 }}</span>
{% endif %}
</div>
<div>
{{ obj1.num }}
{% if obj1.errors.num %}
<span class="error-msg">{{ obj1.errors.num.0 }}</span>
{% endif %}
</div>
<div>
{{ obj1.phone }}
{% if obj1.errors.phone %}
<span class="error-msg">{{ obj1.errors.phone.0 }}</span>
{% endif %}
</div>
<div>
{{ obj1.test }}
</div>
<input type="submit" value="提交" />
</div>
</form>
</body>
</html>

login.html

二、CSRF

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

"""day19_django URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/1.10/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.conf.urls import url, include
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from django.contrib import admin
from app01 import views urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login/', views.login),
url(r'^csrf/', views.csrf),
]

urls.py

from django.shortcuts import render,HttpResponse
from django import forms
from django.forms.utils import ErrorDict
import json
from django.core.exceptions import ValidationError
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=12,
error_messages={'required':'密码必须不能为空',
'min_length':'至少6位',
'max_length':'最多12位'})
num = forms.IntegerField(error_messages={'required':'数字不能为空', 'invalid':'必须输入数字'})
#url = forms.EmailField()
phone = forms.CharField(validators=[mobile_validate, ],)
#生成input标签,并加属性,设置样式
#test = forms.CharField(widget=forms.TextInput(attrs={'k1':'123','class':'error-msg'}))
#生成下拉列表,真正提交数据还是数字
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:
#obj1.errors是ErrorDict,ErrorDict继承dict
# for k,v in objPost.errors.items():
# print(k, v)
# print(objPost.errors['phone'][0])
# print(objPost.errors['user'][0])
# print(objPost.errors['num'][0])
pass
return render(request, 'login.html', {'obj1': objPost})
else:
objGet = LoginForm()
return render(request, 'login.html', {'obj1':objGet}) def csrf(request):
return render(request, 'csrf.html')

views.py

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--form提交-->
<form action="/csrf/" method="POST">
{% csrf_token %}
<input type="text" name="v" />
<input type="submit" value="提交" />
</form> <input type="button" value="Ajax提交" onclick="DoAjax();" />
<!--ajax提交-->
<script src="/static/jquery-2.1.4.min.js"></script>
<script src="/static/jquery.cookie.js"></script>
<script>
//获取cookie
var csrftoken = $.cookie('csrftoken'); function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
}); function DoAjax() {
$.ajax({
url:'/csrf/',
type:'POST',
data:{'k1':'v1'},
success: function (data) {
console.log(data);
}
})
}
</script>
</body>
</html>

csrf.html

三、Cookie和Session

Cookie保存在客户端浏览器上的一个容器,独立存在
服务器上保存的是session(内存或数据库或缓存),依赖Cookie

"""day19_django URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/1.10/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.conf.urls import url, include
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from django.contrib import admin
from app01 import views urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login/', views.login),
url(r'^csrf/', views.csrf),
url(r'^cookie/', views.cookie),
url(r'^cookie1/', views.cookie),
url(r'^log/', views.log),
url(r'^index/', views.index),
url(r'^session_login/', views.session_login),
url(r'^session_index/', views.session_index),
url(r'^session_logout/', views.session_logout),
]

urls.py

from django.shortcuts import render,HttpResponse,redirect
from django import forms
from django.forms.utils import ErrorDict
import json
from django.core.exceptions import ValidationError
import re
from django.views.decorators.csrf import csrf_exempt,csrf_protect
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=12,
error_messages={'required':'密码必须不能为空',
'min_length':'至少6位',
'max_length':'最多12位'})
num = forms.IntegerField(error_messages={'required':'数字不能为空', 'invalid':'必须输入数字'})
#url = forms.EmailField()
phone = forms.CharField(validators=[mobile_validate, ],)
#生成input标签,并加属性,设置样式
#test = forms.CharField(widget=forms.TextInput(attrs={'k1':'123','class':'error-msg'}))
#生成下拉列表,真正提交数据还是数字
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:
#obj1.errors是ErrorDict,ErrorDict继承dict
# for k,v in objPost.errors.items():
# print(k, v)
# print(objPost.errors['phone'][0])
# print(objPost.errors['user'][0])
# print(objPost.errors['num'][0])
pass
return render(request, 'login.html', {'obj1': objPost})
else:
objGet = LoginForm()
return render(request, 'login.html', {'obj1':objGet}) #@csrf_protect 强制给函数加csrf验证 @csrf_exempt
#不用做csrf验证
def csrf(request): return render(request, 'csrf.html') #使用Cookie做登录认证
def cookie(request):
print(request.COOKIES)
obj = render(request, 'cookie.html')
#path='/cookie/',Cookie存放路径
obj.set_cookie('k3','v3',path='/cookie/')
return obj def cookie1(request):
print(request.COOKIES)
obj = render(request, 'cookie.html')
#path='/',Cookie全局生效
obj.set_cookie('k1','v1',path='/')
return obj def log(request):
if request.method == 'POST':
u = request.POST.get('user')
p = request.POST.get('pwd')
if u == 'alex' and p == '':
print(u)
red = redirect('/index/')
red.set_cookie('username', u)
return red
else:
return render(request, 'log.html')
else:
return render(request, 'log.html') def index(request):
user = request.COOKIES.get('username')
if user:
return render(request, 'index.html', {'user':user})
else:
return redirect('/log/') #使用session做登录认证
USER_LIST = ['alex','eric','wang','liu']
def session_login(request):
if request.method == 'POST':
u = request.POST.get('user')
p = request.POST.get('pwd')
if u in USER_LIST and p == '':
request.session['user'] = u
return redirect('/session_index/')
return render(request, 'session_login.html') """
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})
"""
def auth(func):
def inner(request, *args, **kwargs):
#print(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', None)
return render(request, 'session_index.html', {'user':user}) @auth
def session_logout(request):
del request.session['user']
return redirect('/session_login/')

views.py

<!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_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>
<form action="/log/" method="POST">
<input type="text" name="user">
<input type="text" name="pwd">
<input type="submit" value="提交" />
</form>
</body>
</html>

log.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() print(queryset.query) --SQL语句
[UserInfo对象,UserInfo对象,UserInfo对象,] queryset = UserInfo.objects.all().values('user')
[{'user':'alex'},{'user':'eric'}] queryset = UserInfo.objects.all().value_list('user')
[('alex'),('eric')] =======================================================
一对多
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')
#user_type_id #创建UserInfo
1、UserInfo.objects.create(user='alex',pwd='',user_type=UserType.objects.get(id=2))
或:
2、UserInfo.objects.create(user='alex',pwd='',user_type_id=2) #查询
UserInfo.objects.filter(user='alex')
1、查询所有用户类型为普通用户的所有用户名和密码
uid = UserType.objects.get(caption='普通用户').id
UserInfo.objects.filter(user_type_id=uid)
或:
queryset = UserInfo.objects.filter(user_type__caption='普通用户') -- 跨表使用双下划线
[UserInfo对象,UserInfo对象,UserInfo对象,]
row = queryset[0]
row.user
row.pwd
row.user_type -- user_type对象
row.user_type.id
row.user_type.caption
###### objects __
###### row.外键字段.外键表的字段 queryset = UserInfo.objects.filter(user_type__caption='普通用户').values('user', 'user_type__caption') -- 跨表使用双下划线
[{'user':'alex','user_type__caption':'普通用户'},{'user':'eric','user_type__caption':'普通用户'}]
row = queryset[0]
row['user']
row['user_type__caption'] 多张表
class Something(models.Model):
name = models.CharField(max_length=32) class UserType(models.Model):
caption = models.CharField(max_length=32)
st = models.ForeignKey('Something')
#超级管理员、普通用户、访客、黑客 class UserInfo(models.Model):
user = models.CharField(max_length=32)
pwd = models.CharField(max_length=32)
user_type = models.ForeignKey('UserType')
#user_type_id UserInfo.objects.filter(user_type__st__name='xx')