Python全栈之路-Django(十四)
1 Form表单验证内部原理
def login(request):
if request.method == 'GET':
return render(request,'login.html')
else:
obj = LoginForm(request.POST)
# is_valid
"""
1. LoginForm实例化时,
self.fields={
'user': 正则表达式
'pwd': 正则表达式
}
2. 循环self.fields
flag = True
errors
cleaned_data
for k,v in self.fields.items():
# 1. user,正则表达式
input_value = request.POST.get(k)
正则表达式和input_value
flag = False
return flag
"""
if obj.is_valid():
print(obj.cleaned_data)
else:
print(obj.errors)
return render(request,'login.html')
2 Form组件 Ajax提交
urls.py
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'^ajax_login/', views.ajax_login),
url(r'^test/', views.test),
]
views.py
def ajax_login(request):
ret = {'status': True, 'msg': None}
obj = LoginForm(request.POST)
if obj.is_valid():
print(obj.cleaned_data)
return HttpResponse(json.dumps(ret))
else:
print(obj.errors)
ret['status'] = False
ret['msg'] = obj.errors
return HttpResponse(json.dumps(ret))
templates.login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>用户登录</h1>
<form id="f1" action="/login/" method="post">
{% csrf_token %}
<p><input type="text" name="user">{{ obj.errors.user.0 }}</p>
<p><input type="password" name="pwd">{{ obj.errors.pwd.0 }}</p>
<p><input type="submit" value="提交"></p>
<p><input type="button" value="Ajax提交" onclick="ajaxSubmit();"></p>
</form>
<script src="/static/jquery-3.2.1.min.js"></script>
<script>
function ajaxSubmit() {
$('.c1').remove();
$.ajax({
url: '/ajax_login/',
type: 'POST',
data: $('#f1').serialize(),
dataType: "JSON",
success:function (arg) {
console.log(arg);
if (arg.status){
}else{
console.log(arg.msg);
$.each(arg.msg, function (index,value) {
var tag = document.createElement('span');
tag.innerText = value[0];
tag.className = 'c1';
$('#f1').find('input[name="'+index+'"]').after(tag);
})
}
}
})
}
</script>
</body>
</html>
3 Form组件常用字段和参数
3.1 Form组件常用字段
class TestForm(Form):
t1 = fields.CharField(
required=True,
max_length=8,
min_length=2,
error_messages={
'required': 't1不能为空',
'max_length': 't1太长',
'min_length': 't1太短',
}
)
t2 = fields.IntegerField(
max_value=10,
min_value=1000,
error_messages={
'min_value': '必须大于10',
'max_value': '必须小于1000',
'required': 't2不能为空',
'invalid': 't2必须是数字'
}
)
t3 = fields.EmailField(
error_messages={
'required': 't3不能为空',
'invalid': 't3必须是邮箱'
}
)
t4 = fields.URLField()
t5 = fields.SlugField() # 字符串只能包含数字、字母、下划线等字符
t6 = fields.GenericIPAddressField()
t7 = fields.DateField()
t8 = fields.DateTimeField()
t9 = fields.RegexField(
'139\d+',
error_messages={
'invalid': '输入一个有效的值'
}
) # 自定义正则表达式 包含:1 是否为空 2 最长 3 最短 4 自定义规则
3.1 Form组件常用参数
class TestForm(Form):
t1 = fields.CharField(
required=True,
# 用于生成HTML标签并保留用户上次输入的数据 只推荐使用widget
widget=widgets.Textarea, # 自动生成HTML标签
label='用户名', # 前端可以通过obj.t1.label访问
initial='root', # 在input框中显示默认值
help_text='请输入用户名...', # 提供帮助信息
label_suffix=':', # Label内容后缀
# validators=[], # 自定义正则表达式
disabled=True, # 是否可编辑
max_length=8,
min_length=2,
error_messages={
'required': 't1不能为空',
'max_length': 't1太长',
'min_length': 't1太短',
}
)
4 Form组件保留上次输入数据示例
app01.views.py
class RegisterForm(Form):
user = fields.CharField(min_length=8)
email = fields.EmailField()
password = fields.CharField(min_length=8, max_length=16)
phone = fields.RegexField('139\d+')
def register(request):
if request.method == 'GET':
obj = RegisterForm()
return render(request, 'register.html', {'obj': obj})
else:
obj = RegisterForm(request.POST)
if obj.is_valid():
print(obj.cleaned_data)
else:
print(obj.errors)
return render(request, 'register.html', {'obj': obj})
templates.register.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/register/" method="post" novalidate>
{% csrf_token %}
<p>{{ obj.user }}{{ obj.errors.user.0 }}</p>
<p>{{ obj.email }}{{ obj.errors.email.0 }}</p>
<p>{{ obj.password }}{{ obj.errors.password.0 }}</p>
<p>{{ obj.phone }}{{ obj.errors.phone.0 }}</p>
<input type="submit" value="提交">
</form>
</body>
</html>
5 利用Form组件实现班级管理和学生管理
urls.py
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^classes/', views.classes),
url(r'^add_class/', views.add_class),
url(r'^edit_class/(\d+)/', views.edit_class),
url(r'^students/', views.students),
url(r'^add_student/', views.add_student),
url(r'^edit_student/(\d+)/', views.edit_student),
]
app01.models.py
from django.db import models
# Create your models here.
class Classes(models.Model):
title = models.CharField(max_length=32)
class Student(models.Model):
name = models.CharField(max_length=32)
email = models.CharField(max_length=32)
age = models.IntegerField()
cls_id = models.ForeignKey('Classes')
class Teacher(models.Model):
tname = models.CharField(max_length=32)
c2t = models.ManyToManyField('Classes')
app01.views.py
from django.shortcuts import render, redirect
from app01 import models
# Create your views here.
from django.forms import Form, fields
from django.forms import widgets
class ClassForm(Form):
title = fields.RegexField(
'全栈\d+期',
error_messages={
'required': '不能为空',
'invalid': '格式错误'
}
)
def classes(request):
if request.method == 'GET':
class_list = models.Classes.objects.all()
return render(request, 'classes.html', {'class_list': class_list, })
def add_class(request):
if request.method == 'GET':
obj = ClassForm()
return render(request, 'add_class.html', {'obj': obj})
else:
obj = ClassForm(request.POST)
if obj.is_valid():
models.Classes.objects.create(**obj.cleaned_data)
return redirect('/classes/')
else:
print(obj.errors)
return render(request, 'add_class.html', {'obj': obj})
def edit_class(request, nid):
if request.method == 'GET':
row = models.Classes.objects.filter(id=nid).first()
# 下面是两种让页面显示初始值的方法
# obj = ClassForm(data={'title': row.title}) # 会对默认值进行校验
obj = ClassForm(initial={'title': row.title}) # 不会对默认值进行校验
return render(request, 'edit_class.html', {'nid': nid, 'obj': obj})
else:
obj = ClassForm(request.POST)
if obj.is_valid():
print(obj.cleaned_data)
models.Classes.objects.filter(id=nid).update(**obj.cleaned_data)
return redirect('/classes/')
print(obj.errors)
return render(request, 'edit_class.html', {'nid':nid, 'obj': obj})
class StudentForm(Form):
name = fields.CharField(
max_length=10,
min_length=2,
widget=widgets.TextInput(attrs={'class': 'form-control'})
)
email = fields.EmailField(
widget=widgets.TextInput(attrs={'class': 'form-control'}),
)
age = fields.IntegerField(
min_value=20,
max_value=30,
widget=widgets.TextInput(attrs={'class': 'form-control'})
)
cls_id_id = fields.IntegerField(
# widget=widgets.Select(choices=[(1,'上海'), (2,'北京')]),
widget=widgets.Select(
choices=models.Classes.objects.all().values_list('id', 'title'),
attrs={'class': 'form-control'}
)
)
def students(request):
stu_list = models.Student.objects.all().values('id', 'name', 'age', 'email', 'cls_id__title')
return render(request, 'students.html', {'stu_list': stu_list})
def add_student(request):
if request.method == 'GET':
obj = StudentForm()
return render(request, 'add_student.html', {'obj': obj})
else:
obj = StudentForm(request.POST)
if obj.is_valid():
print(obj.cleaned_data)
models.Student.objects.create(**obj.cleaned_data)
return redirect('/students/')
else:
print(obj.errors)
return render(request, 'add_student.html', {'obj': obj})
def edit_student(request, nid):
if request.method == 'GET':
row = models.Student.objects.filter(id=nid).values().first()
obj = StudentForm(row)
return render(request, 'edit_student.html', {'nid': nid, 'obj': obj})
else:
obj = StudentForm(request.POST)
if obj.is_valid():
models.Student.objects.filter(id=nid).update(**obj.cleaned_data)
return redirect('/students/')
else:
print(obj.errors)
return render(request, 'edit_student.html', {'nid': nid, 'obj': obj})
templates.classes.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>班级列表</h1>
<div>
<a href="/add_class/">添加</a>
</div>
<ul>
{% for row in class_list %}
<li>{{ row.id }} {{ row.title }} <a href="/edit_class/{{ row.id }}/">编辑</a></li>
{% endfor %}
</ul>
</body>
</html>
templates.add_class.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>添加班级</h1>
<form action="/add_class/" method="post" novalidate>
{% csrf_token %}
<p>{{ obj.title }}{{ obj.errors.title.0 }}</p>
<input type="submit" value="提交">
</form>
</body>
</html>
templates.edit_class.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>编辑班级</h1>
<form action="/edit_class/{{ nid }}/" method="post">
{% csrf_token %}
<p>{{ obj.title }}{{ obj.errors.title.0 }}</p>
<input type="submit" value="提交">
</form>
</body>
</html>
templates.students.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>学生列表</h1>
<a href="/add_student/">添加</a>
<ul>
{% for stu in stu_list %}
<li>{{ stu.id }}-{{ stu.name }}-{{ stu.age }}-{{ stu.email }}-{{ stu.cls_id__title }} <a href="/edit_student/{{ stu.id }}/">编辑</a></li>
{% endfor %}
</ul>
</body>
</html>
templates.add_student.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>添加学生</h1>
<form action="/add_student/" method="post" novalidate>
{% csrf_token %}
<p>{{ obj.name }}</p>
<p>{{ obj.email }}</p>
<p>{{ obj.age }}</p>
<p>{{ obj.cls_id_id }}</p>
<input type="submit" value="提交">
</form>
</body>
</html>
templates.edit_student.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/static/plugins/bootstrap-3.3.7-dist/css/bootstrap.css"></link>
</head>
<body>
<div style="width: 500px;margin: 10px auto;">
<form class="form-horizontal" action="/edit_student/{{ nid }}/" method="post" novalidate>
{% csrf_token %}
<div class="form-group">
<label class="col-sm-2 control-label">姓名</label>
<div class="col-sm-10">
{{ obj.name }}
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">邮箱</label>
<div class="col-sm-10">
{{ obj.email }}
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">年龄</label>
<div class="col-sm-10">
{{ obj.age }}
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">班级</label>
<div class="col-sm-10">
{{ obj.cls_id_id }}
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">Submit</button>
</div>
</div>
</form>
</div>
</body>
</html>