一.form进阶
1.字段批量添加样式:
def __init__(self,*args,**kwargs):
super(BookForm,self).__init__(*args,**kwargs)
for field in self.fields.values():
field.widget.attrs.update({'class':'form-control'})
解释:
1.fields.values:所有的值 字段名是key
2.widget.attrs.update :字典中更新一条记录
2.form版本图书管理系统:
校验类BookForm:
from django import forms
class BookForm(forms.Form):
title = forms.CharField(
max_length=32,
min_length=12,
label='书名',
)
publishDate = forms.DateField(
label='出版日期',
widget=forms.widgets.TextInput(attrs={'type':'date'})
)
price = forms.DecimalField(
max_digits=5,
decimal_places=2,
label='价格',
)
publishs = forms.ModelChoiceField( #如果想用数据库中数据进行展示需要用model
label='出版社',
queryset=app02.models.Publish.objects.all(), #直接把所有数据查出来
widget=forms.widgets.Select()
)
authors = forms.ModelMultipleChoiceField(
label='作者',
queryset=app02.models.Author.objects.all(),
widget=forms.widgets.SelectMultiple(),
)
前端页面:
视图函数中:
添加书籍:
# 添加数据
def add_book(request):
if request.method == 'GET':
book_forms = BookForm()
return render(request, 'many_test/book_add.html', {'book_forms':book_forms})
else:
book_forms = BookForm(request.POST)
if book_forms.is_valid():
print(book_forms.cleaned_data) #通过的数据
authors = book_forms.cleaned_data.pop('authors') #将多对多的数据取出来
new_book = app02.models.Book.objects.create(**book_forms.cleaned_data)
new_book.authors.add(*authors) #保存多对多的关系
return redirect('app03:show_book')
else:
print(book_forms.errors) #错误信息
return render(
request, 'many_test/book_add.html',
{'book_forms': book_forms}) #如果有错误将页面再返回 此时book_forms是有值的
#以前的写法:
# authors = request.POST.getlist('authors')
# all_data = request.POST.dict()
# del all_data['csrfmiddlewaretoken']
# del all_data['authors']
# book_obj = app02.models.Book.objects.create(**all_data)
# book_obj.authors.add(*authors)
# return redirect('app03:show_book')
展示书籍:
# 展示书籍
def show_book(request):
start = 0
book_list = app02.models.Book.objects.all()
paginator = Paginator(book_list, 2) # 创建一个panginator对象
page = request.GET.get('page', 1)
currentPage = int(page)
if currentPage != 1:
start = (currentPage - 1) * 2
try:
book_list = paginator.page(page)
except PageNotAnInteger:
book_list = paginator.page(1) # 这个是对你的分页的数据进行取值 去除你的分页过后的第一页
except EmptyPage:
book_list = paginator.page(paginator.num_pages) # 分页数
return render(
request, 'manytable/show_book.html',
{'paginator': paginator, 'book_list': book_list, 'currentPage': currentPage, 'start': start})
编辑书籍:
# 编辑书籍
def edit_book(request, book_id):
book_obj = app02.models.Book.objects.filter(pk=book_id)
print(book_obj.values())
if request.method == 'GET':
book_forms = BookForm(book_obj.values()[0])
return render(request, 'many_test/book_edit.html', {'book_forms': book_forms,'book_obj':book_obj})
else:
pass
编辑书籍页面效果:
可以看到我们用form去做编辑时没有将出版社和作者信息给选中,如果要选中的话就需要用我们之前的那种判断方式,比较麻烦,所以这块需要用到下面的ModelForm来解决。
删除书籍:
# 删除书籍
def delete_book(request, book_id):
app02.models.Book.objects.filter(pk=book_id).delete()
return redirect('app03:show_book')
二.ModelForm
组件的功能就是把model和form组合起来,会把所有的字段信息转换成forms里面的字段(上面定义的BookForm),校验规则就是我们数据库中定义的,但是我们也可以在ModelForm里面自己定义,这样就会覆盖我们model里面的那个字段。
创建ModelForm类:
from django.forms import ModelForm
class BookModelForm(ModelForm):
#title = forms.CharField(max_length=16) 如果这里也定义了一个title,那就会把你数据库里面的title给替换掉
class Meta: #原类Meta(规定写法,并注意首字母是大写的)
model = app02.models.Book #指定book表 全部转换成上面BookForm里面的校验数据
fields = '__all__' #指定表里面的所有的字段 告诉Book表将表里面所有的字段信息全部给我生成forms里面的字段
exclude = ['title'], #排除
error_messages = { #错误信息
'title':{'required':'不能为空!!'},
'price':{'required':'不能为空!!'},
'publishs':{'required':'不能为空!!'},
'publishDate':{'required':'不能为空!!'},
'authors':{'required':'不能为空!!'},
},
help_texts = {'title':'书名!'} #帮助信息
widgets = {} #添加样式
#全局钩子
def clean(self):
pass
# 局部钩子
def clean_title(self):
value = self.cleaned_data.get('title')
if '666' in value:
raise ValidationError('敏感词汇!!666')
else:
return value
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
for field in self.fields.values():
field.widget.attrs.update({'class':'form-control'})
ModelForm版本图书管理系统:
添加书籍:
# 添加数据
def add_book(request):
if request.method == 'GET':
book_model_form = BookModelForm()
return render(request, 'many_test/book_add.html', {'book_model_form':book_model_form})
else:
book_model_form = BookModelForm(request.POST)
if book_model_form.is_valid():
print(book_model_form.cleaned_data)
book_model_form.save() #直接保存 因为上面定义了model = app02.models.Book
return redirect('app03:show_book')
else:
print(book_model_form.errors)
return render(request, 'many_test/book_add.html', {'book_model_form': book_model_form})
书籍展示:
# 展示书籍
def show_book(request):
start = 0
book_list = app02.models.Book.objects.all()
paginator = Paginator(book_list, 5) # 创建一个panginator对象
page = request.GET.get('page', 1)
currentPage = int(page)
if currentPage != 1:
start = (currentPage - 1) * 5
try:
book_list = paginator.page(page)
except PageNotAnInteger:
book_list = paginator.page(1) # 这个是对你的分页的数据进行取值 去除你的分页过后的第一页
except EmptyPage:
book_list = paginator.page(paginator.num_pages) # 分页数
return render(
request, 'many_test/book_show.html',
{'paginator': paginator, 'book_list': book_list, 'currentPage': currentPage, 'start': start})
编辑书籍:
# 编辑书籍
def edit_book(request, book_id):
book_obj = app02.models.Book.objects.filter(pk=book_id)
book_obj = book_obj.first()
if request.method == 'GET':
book_model_form = BookModelForm(instance=book_obj) #需要指定给那个实例编辑
return render(request, 'many_test/book_edit.html', {'book_model_form': book_model_form,'book_obj':book_obj})
else:
book_model_form = BookModelForm(
request.POST,instance=book_obj) #这里也需要指定一下,不然下面的save会新增加一条
if book_model_form.is_valid():
book_model_form.save()
return redirect('app03:show_book')
else:
return render(request, 'many_test/book_edit.html',
{'book_model_form': book_model_form, 'book_obj': book_obj})
删除书籍:
# 删除书籍
def delete_book(request, book_id):
app02.models.Book.objects.filter(pk=book_id).delete()
return redirect('app03:show_book')
html文件:
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
</head>
<body>
<form action="" method="post">
{% csrf_token %}
{% for bookform in book_model_form %}
<div>
<label for="{{ bookform.id_for_label }}">{{ bookform.label }}</label>
{{ bookform }}
<span style="color: red;font-size: 14px">{{ bookform.errors.0 }}</span>
</div>
{% endfor %}
<input type="submit">
</form>
</body>
</html>
实际上我们的编辑和添加页面是内容是重复的,可以做一个base模板,用incloud调用就行了:
base:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% for bookform in book_model_form %}
<div>
<label for="{{ bookform.id_for_label }}">{{ bookform.label }}</label>
{{ bookform }}
<span style="color: red;font-size: 14px">{{ bookform.errors.0 }}</span>
</div>
{% endfor %}
</body>
</html>
add_book:
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
</head>
<body>
<h1>添加书籍</h1>
<form action="" method="post">
{% csrf_token %}
{% include 'many_test/base.html' %}
<input type="submit">
</form>
</body>
</html>
edit_book:
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
</head>
<body>
<h1>编辑书籍</h1>
<form action="" method="post">
{% csrf_token %}
{% include 'many_test/base.html' %}
<input type="submit">
</form>
</body>
</html>