目录标题
一:批量插入数据
1.urls.py
urlpatterns = [
# 批量插入数据
path('index/', views.index)
]
2.views.py
def index(request):
l = []
for i in range(10000):
l.append(models.Book(title='第%s本书' % i))
models.Book.objects.bulk_create(l)
return render(request, 'index.html', locals())
3.html页面
<body>
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
{% for book in l %}
<P>{{ book.title }}</P>
{% endfor %}
</div>
</div>
</div>
</body>
总结:如何批量插入数据
- 1.首先自定义一个空的列表
- 2.把每一条数据通过append方法添加到自定的列表中
- 3.最后通过bulk_create方法把自定义列表添加到数据库中
补充知识点:
通过bulk_update方法,实现对数据库中数据的批量修改
二:自定义分页器(要会使用)
1.自定义分页器代码
class Pagination(object):
def __init__(self,current_page,all_count,per_page_num=2,pager_count=11):
"""
封装分页相关数据
:param current_page: 当前页
:param all_count: 数据库中的数据总条数
:param per_page_num: 每页显示的数据条数
:param pager_count: 最多显示的页码个数
用法:
queryset = model.objects.all()
page_obj = Pagination(current_page,all_count)
page_data = queryset[page_obj.start:page_obj.end]
获取数据用page_data而不再使用原始的queryset
获取前端分页样式用page_obj.page_html
"""
try:
current_page = int(current_page)
except Exception as e:
current_page = 1
if current_page <1:
current_page = 1
self.current_page = current_page
self.all_count = all_count
self.per_page_num = per_page_num
# 总页码
all_pager, tmp = divmod(all_count, per_page_num)
if tmp:
all_pager += 1
self.all_pager = all_pager
self.pager_count = pager_count
self.pager_count_half = int((pager_count - 1) / 2)
@property
def start(self):
return (self.current_page - 1) * self.per_page_num
@property
def end(self):
return self.current_page * self.per_page_num
def page_html(self):
# 如果总页码 < 11个:
if self.all_pager <= self.pager_count:
pager_start = 1
pager_end = self.all_pager + 1
# 总页码 > 11
else:
# 当前页如果<=页面上最多显示11/2个页码
if self.current_page <= self.pager_count_half:
pager_start = 1
pager_end = self.pager_count + 1
# 当前页大于5
else:
# 页码翻到最后
if (self.current_page + self.pager_count_half) > self.all_pager:
pager_end = self.all_pager + 1
pager_start = self.all_pager - self.pager_count + 1
else:
pager_start = self.current_page - self.pager_count_half
pager_end = self.current_page + self.pager_count_half + 1
page_html_list = []
# 添加前面的nav和ul标签
page_html_list.append('''
<nav aria-label='Page navigation>'
<ul class='pagination'>
''')
first_page = '<li><a href="?page=%s">首页</a></li>' % (1)
page_html_list.append(first_page)
if self.current_page <= 1:
prev_page = '<li class="disabled"><a href="#">上一页</a></li>'
else:
prev_page = '<li><a href="?page=%s">上一页</a></li>' % (self.current_page - 1,)
page_html_list.append(prev_page)
for i in range(pager_start, pager_end):
if i == self.current_page:
temp = '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i,)
else:
temp = '<li><a href="?page=%s">%s</a></li>' % (i, i,)
page_html_list.append(temp)
if self.current_page >= self.all_pager:
next_page = '<li class="disabled"><a href="#">下一页</a></li>'
else:
next_page = '<li><a href="?page=%s">下一页</a></li>' % (self.current_page + 1,)
page_html_list.append(next_page)
last_page = '<li><a href="?page=%s">尾页</a></li>' % (self.all_pager,)
page_html_list.append(last_page)
# 尾部添加标签
page_html_list.append('''
</nav>
</ul>
''')
return ''.join(page_html_list)
如何使用自定义分页器
- 步骤1:首相在应用文件下建一个文件夹(plugins),再在这个文件夹中建一个py文件(mypage.py),把自定义分页器代码粘贴进去
- 步骤2:在需要分页的视图函数中写入一下代码
def index(request):
from app01.plugins import mypage
book_query = models.Book.objects.all()
page_obj = mypage.Pagination(current_page=request.GET.get('page'),
all_count=book_query.count()
)
page_query = book_query[page_obj.start:page_obj.end]
return render(request, 'index.html', locals())
- 步骤3:在需要分页的html页面中写入以下代码
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
{% for book_obj in page_query %}
<p class="text-center">{{ book_obj.title }}</p>
{% endfor %}
{{ page_obj.page_html|safe }}
</div>
</div>
</div>
三:forms组件
1.forms组件具有的功能
- 1.数据校验:支持提前设置各种校验规则,之后自动校验
- 2.渲染画面:支持直接渲染获取用户数据的各种标签
- 3.展示信息:支持针对不同的校验失败,展示不同的提示信息
2.forms类的产生
from django import forms
class MyForms(forms.Form):
"""下面每个字段,都必须要符合括号中的条件,或者forms组件隐藏的特点条件"""
name = forms.CharField(min_length=3, max_length=8)
pwd = forms.IntegerField(min_value=3, max_value=8)
email = forms.EmailField()
3.forms组件之数据校验
直接在pycharm自带的测试工具中测试:
from app01 import models
from app01 import views
form_obj = views.MyForms({'name':'jason','pwd':123,'email':121})
form_obj.is_valid()
False
form_obj.cleaned_data
{'name': 'jason'}
form_obj.errors
{'pwd': ['Ensure this value is less than or equal to 8.'], 'email': ['Enter a valid email address.']}
总结:
- 1.首先导入要测试的文件
- 2.准备好测试数据,并且以字典的形式传入,同时生成测试对象
- 3.object.is_valid() 该方法只有在所有的数据都合法的情况下,才会返回True
- 4.object.cleaned_data 返回所有符合校验规则的数据
- 5.object.errors 返回不符合校验规则的数据,以及不符合规则的原因
补充总结:
- 1.只校验类中出现的字段,多传没影响,不会报错
- 2.少传会直接报错
4.forms组件之渲染标签
- 步骤1:写一个视图函数,产生一个forms类的空对象,把这个空对象直接传到html页面上
def index1(request):
# 1.先产生一个空对象
forms_obj = MyForms()
# 2.直接把空对象传递给html页面
return render(request, 'index1.html',locals())
- 步骤2:在html页面中通过对象点的方式得到表中字段对应的标签
- 方式1(封装程度高 扩展性差)
{{ form_obj.as_p }}
{{ form_obj.as_table }}
{{ form_obj.as_ul }}
- 方式2(封装程度低 扩展性好 编写困难)
{{ form_obj.name.lable }}
{{ form_obj.name }}
- 方式3(推荐使用)
{% for form in form_obj %}
<p>{{ form.label }}{{ form }}</p>
{% endfor %}
5.forms组件之展示提示信息
views.py
from django import forms
class MyForms(forms.Form):
name = forms.CharField(min_length=3, max_length=8, label='用户名',
error_messages={
'min_length': '用户名最少为3个字符',
'max_length': '用户名最大为8个字符',
'required': '用户名不能为空'
}
)
pwd = forms.CharField(min_length=3, max_length=8, label='密码')
confirm_pwd = forms.CharField(min_length=3, max_length=8, label='确认密码')
email = forms.EmailField(label='邮箱',
error_messages={
'invalid': '邮箱格式不正确'
}
)
def index1(request):
# 1.先产生一个空对象
forms_obj = MyForms()
if request.method == 'POST':
# 3.校验数据
forms_obj = MyForms(request.POST) # request.POST 就是一个字典
# 4.校验数据是否合法
if forms_obj.is_valid():
# 5.如果合法 操作数据库存储数据
pass
# 6.如果不合法 错误信息会展示到前端
# 2.直接把空对象传递给html页面
return render(request, 'index1.html',locals())
html页面
<form action="" method="post" novalidate>
{% for form in forms_obj %}
<p>
{{ form.label }}{{ form }}
<span style="color: red">{{ form.errors.0 }}</span>
</p>
{% endfor %}
<input type="submit">
</form>
总结:
- 1.想要取消前端页面的校验功能,直接在form标签中加入属性:novalidate
- 2.get请求和post请求传给html页面对象的变量名必须一样(视图函数中的两个:forms_obj要一样)
- 3.两个form_obj的作用:forms组件当你的数据不合法的时候情况下,会保存你上次的数据,让你基于上次的基础上进行修改数据,更加的便捷
- 4.error_message可以自定义错误提示信息
- 5.label可以自定义字段名称,即可以定义成汉字
- 6.由于form.errors是一个列表,所以不许点0,拿到第一条数据
四:钩子函数
注意:钩子函数必须写在forms类中
1.分类:
- 1.局部钩子:单个字段的校验,类似于第二道校验关卡
- 2.全局钩子:多个字段的校验,类似于第二道校验关卡
2.局部钩子案例:校验name字段
def clean_name(self):
# 1.获取用户名
name = self.cleaned_data.get('name')
if 'h' in name:
# 提示前端展示错误信息
self.add_error('name', '名字中不能出现h')
# 将钩子函数勾取的数据返回回去
return name
3.全局钩子案例:校验pwd和comfirm_pwd
def clean(self):
pwd = self.cleaned_data.get('pwd')
confirm_pwd = self.cleaned_data.get('confirm_pwd')
if not pwd == confirm_pwd:
self.add_error('confirm_pwd', '两次密码不一致')
return self.cleaned_data
五:forms组件重要参数
1.基本参数
参数 | 作用 |
---|---|
label | 字段注释 |
error_messages | 错误提示 |
required | 是否为空 |
initial | 默认值 |
validators | 正则校验 |
widget | 标签类型、标签属性 |
2.widget参数
- input
widget=forms.widgets.TextInput(attrs={'class': 'form-control c1 c2', 'username': 'jason'})
- password
pwd = forms.CharField(
min_length=6,
label="密码",
widget=forms.widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True)
)
- radioSelect
gender = forms.fields.ChoiceField(
choices=((1, "男"), (2, "女"), (3, "保密")),
label="性别",
initial=3,
widget=forms.widgets.RadioSelect()
- 单选select
hobby = forms.ChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
label="爱好",
initial=3,
widget=forms.widgets.Select()
)
- 多选select
hobby = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
label="爱好",
initial=[1, 3],
widget=forms.widgets.SelectMultiple()
)
- 单选checkbox
keep = forms.ChoiceField(
label="是否记住密码",
initial="checked",
widget=forms.widgets.CheckboxInput()
)
- 多选checkbox
hobby = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=[1, 3],
widget=forms.widgets.CheckboxSelectMultiple()
)
总结:
- 1.多个属性值的话,直接用逗号隔开
3.validators正则校验
RegexValidator(r'^[0-9]+$','请输入数字')
六:modelform组件
1.modelform是forms组件的优化版本,使用更加简单
views.py
class MyModelForm(forms.ModelForm):
class Meta:
model = models.User
fields = '__all__'
exclude = ('age',) # 把某个字段排除在外
def clean_name(self):
name = self.cleaned_data.get('name')
res = models.User.objects.filter(name=name).first()
if res:
self.add_error('name', '用户名已存在')
return name
def md(request):
modelform_obj = MyModelForm()
if request.method == 'POST':
modelform_obj = MyModelForm(request.POST)
if modelform_obj.is_valid():
modelform_obj.save() # 保存数据
return render(request, 'md.html', locals())
html文件
<body>
<form action="" method="post" novalidate>
{% for model in modelform_obj %}
<p>
{{ model.label }}{{ model }}
<span>{{ model.errors.0 }}</span>
</p>
{% endfor %}
<input type="submit">
</form>
</body>