批量数据操作
1.批量数据添加方式
1.1 通过create添加
产生数据后持续性向数据库添加数据 容易导致数据库崩掉(数据过多不适用)
def func(request):
for i in range(10000):
models.Func.objects.create(num=f'第{i}张') # 持续添加数据量过大容易导致系统崩掉
func_list = models.Func.objects.all()
return render(request, 'func.html', locals())
{% for func in func_list %}
<p>{{ func.num }}</p>
{% endfor %}
1.2 通过bulk_create添加
先产生所有数据 一次性添加至数据库(适用于批量数据处理)
def func(request):
# func_list = [] # 创建空列表存放数据对象
# for i in range(100000):
# func_obj = models.Func(num=f'第{i}张')
# func_list.append(func_obj) # 添加产生的数据对象至列表
# 上述四行可以写成列表生成式
func_list = [models.Func(num=f'第{i}张') for i in range(100000)]
models.Func.objects.bulk_create(func_list)
func_list = models.Func.objects.all()
return render(request, 'func.html', locals())
分页器操作
自定义分页器
1.分页器推导流程
1.获取所有数据并用count进行条数计算
2.对批量数据进行分页展示(获取的数据是列表套对象 可以采用切片操作)
3.规定每页显示的条数
4.设置分页
5.获得总分页数用divmod获得整数与余数(有余数则总页数=整数+1)
6.获取用户选择的页数(用异常捕获对值错误页数保持在第一页)
7.设置页面起始数据条数并展示到前端页面
start_num = (用户选择的页数-1)*每页展示条数
end_num = 用户选择的页数*每页展示条数
8.前端html页面无法进行总页数循环展示(无range操作)在后端写好后传入
9.在后端逻辑层面编写所有分页展示代码编写(可以设置成奇数展示 对称)
设置传入前端页面的分页数等于空字符串
规定每页的分页数(用用户选择的页码数对起始终止位置进行设置 如起始=用户选择页-3 终止=用户页+4)
存在问题:起始第4条与终止第3条会出现负数页码及无数据情况
解决办法:在逻辑编写分页展示之前进行用户选择与起始4条及终止3条页面数据比对判断(前面先设置变量=用户选择页面 如果小于起始第四条或大于终止第三条 则使展示页在此基础上不再发生改变)
for循环获取每页上面分页数 对于用户选择的页数进行标识(用class="active"方便查看)
2.分页器推导代码
视图层代码:
def func(request):
# 获取用户选择的页数
choice_page = request.GET.get('page', 1) # 网址后缀后面写?page=页数可以切换
try:
choice_page = int(choice_page)
except ValueError:
choice_page = 1
func_list = models.Func.objects.all()
# 确定每页展示条数
reveal_page = 10
# 获取页面起始条数
start_page = (choice_page-1)*reveal_page
end_page = choice_page*reveal_page
page_list = models.Func.objects.all()[start_page:end_page] # 可以通过索引取值获取展示页数
# 获取总的条数
sum_num = func_list.count()
# 获取总页数
int_page, float_page = divmod(sum_num, reveal_page)
print(int_page)
# 判断是否存在余数
if float_page:
int_page += 1
# html中没有range操作 不能直接循环展示页面 所在在后端操作好之后传给前端页面
html_page = ''
# for page in range(1, int_page+1): # 展示的是所有分页签 需要控制数量 不能在用所有页变量 可以使用用户选择的页数加一定数量表示
user_choice_page = choice_page
if choice_page < 4:
user_choice_page = 4
if choice_page > int_page-3:
user_choice_page = int_page-3
for page in range(user_choice_page-3, user_choice_page+4): # 这样操作前三页 及后三页会存在负页及没有数据问题
if page == choice_page:
html_page += '<li class="active"><a href="?page=%s">%s</a></li>' % (page, page)
else:
html_page += '<li><a href="?page=%s">%s</a></li>' % (page, page)
return render(request, 'func.html', locals())
模板层代码:
{% for func in page_list %}
<p class="text-center">{{ func.num }}</p>
{% endfor %}
</li>
{{ html_page|safe }} <!--需要安全校验-->
<li>
模型层代码:
urlpatterns = [
path('admin/', admin.site.urls),
path('func/', views.func)
]
3.自定义分页器代码
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, 'bookList.html', locals())
{% for book_obj in page_query %}
<p class="text-center">{{ book_obj.title }}</p>
{% endfor %}
{{ page_obj.page_html|safe }}
form组件
简介
1.数据校验:支持提前设置各种校验规则 之后自动校验
2.渲染页面:支持直接渲染获取用户数据的各种标签
3.展示信息:支持针对不同的校验失败展示不同的提示
4.用户信息校验:
路由层代码:
urlpatterns = [
path('admin/', admin.site.urls),
path('userinfo/', views.userinfo)
]
视图层代码:
def userinfo(request):
# 设置一个空的键值对
info_dict = {'username': '', 'password': ''}
# 获取用户输入的信息
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
email = request.POST.get('email')
# 对用户输入的数据做校验
if username == 'lili':
info_dict['username'] = 'lili用户名不可以使用'
if password == '123':
info_dict['password'] = '笨蛋密码太简单了吧 咋和你的脑回路一样简单'
return render(request, 'userinfo.html', locals())
模板层代码:
<form action="" method="post">
<p>用户名:
<input type="text" name="username">
<span style="color: red">{{ info_dict.username }}</span>
</p>
<P>密码:
<input type="text" name="password">
<span style="color: red">{{ info_dict.password }}</span>
</P>
<p>
<input type="submit" value="提交">
</p>
</form>
5.form组件创建
# 编写form类
from django import forms
class MyForm(forms.Form):
name = forms.CharField(min_length=3, max_length=8)
age = forms.IntegerField(min_value=0, max_value=110)
email = forms.EmailField()
数据校验
1.数据校验功能
1.1 传递待校验的数据:
1.2 判断所有数据是否符合校验:form_obj.is_valid()
1.3 获取符合校验规则的数据:form_obj.cleaned_data
1.4 查询不符合校验规则的数据及错误原因:form_obj.errors
2.代码操作:
# 编写form类
from django import forms
class MyForm(forms.Form):
name = forms.CharField(min_length=3, max_length=8)
age = forms.IntegerField(min_value=0, max_value=110)
email = forms.EmailField()
from app01 import views
form_obj = views.MyForm({'name':'lili', 'age': 18, 'email':123})
form_obj.is_valid() # False 判断所有数据是否正确
form_obj.cleaned_data # {'name': 'lili', 'age': 18} 正确数据
form_obj.errors # {'email': ['Enter a valid email address.']} 错误数据
渲染标签功能
1.渲染标签
1.1 封装程度高 扩展性差
{{ form_obj.as_p }} # 产生p标签及input框 分行展示
{{ form_obj.as_table }} # 产生input框 一行展示
{{ form_obj.as_ul }} # 产生input框 产生列表表示(无序列表)
1.2 封装程度低 扩展性好 编写困难
{{ form_obj.name.label }} # 产生所点字段名大写
{{ form_obj.name }} # 产生input框
1.3 封装程度低 扩展性好
{% for form in form_obj %} # for循环展示所有数据字段
<p>{{ form.label }}{{ form }}</p> # 产生所有数据字段名大写 产生input框
{% endfor %}
注:类以外的标签不会被自动渲染 需要自己编写
展示提示信息
1.展示信息:通过form表单取消浏览器自动添加的数据校验功能
2.代码操作:
路由层代码:
urlpatterns = [
path('admin/', admin.site.urls),
path('user_info/', views.user_info)
]
视图层代码:
def user_info(request):
form_obj = MyForm()
if request.method == 'POST':
form_obj = MyForm(request.POST)
if form_obj.is_valid():
print(form_obj.cleaned_data)
return render(request, 'user_info.html', locals())
模板层代码:
<form action="" method="post" novalidate> # 转换请求类型 取消前端数据校验
{% for form in form_obj %}
<p>{{ form.label }}{{ form }}
<span style="color: red">{{ form.errors.0 }}</span> # form.errors.0 取值
</p>
{% endfor %}
<p>
<input type="submit" value="提交">
</p>
字段常见参数
| 字段参数 | 作用 |
|---|---|
| max_length | 最大长度 |
| min_length | 最小长度 |
| label | 字段注释 |
| error_messages | 错误提示 |
| required | 是否为空 |
| widget | 标签类型、标签属性 |
| initial | 默认值 |
| validators | 正则校验 |
钩子函数
局部钩子
1.局部钩子:校验单个字段
2.代码操作:
class MyForm(forms.Form):
name = forms.CharField(min_length=3, max_length=8)
age = forms.IntegerField(min_value=0, max_value=110)
email = forms.EmailField()
pwd = forms.IntegerField()
confirm_pwd = forms.IntegerField()
def clean_name(self):
name =self.cleaned_data.get('name')
res = models.UserInfo.objects.filter(name=name).first()
if res:
return self.add_error('name', '已经注册过啦 傻了吗?')
return name # 用完记得还回去呀
def user_info(request):
form_obj = MyForm()
if request.method == 'POST':
form_obj = MyForm(request.POST)
if form_obj.is_valid():
res = form_obj.cleaned_data
res.pop('confirm_pwd')
models.UserInfo.objects.create(**res)
return render(request, 'user_info.html', locals())

全局钩子
1.全局钩子:校验多个字段
def clean(self):
pwd = self.cleaned_data.get('pwd')
confirm_pwd = self.cleaned_data.get('confirm_pwd')
# 判断
if not pwd == confirm_pwd:
return self.add_error('confirm_pwd', '两次密码不一致')
return self.cleaned_data # 拿出了所有数据 需要返回所有数据

源代码
1.self._clean_fields()
def _clean_fields(self):
for name, field in self.fields.items():
if field.disabled:
value = self.get_initial_for_field(field, name)
else:
value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
try:
if isinstance(field, FileField):
initial = self.get_initial_for_field(field, name)
value = field.clean(value, initial)
else:
value = field.clean(value)
self.cleaned_data[name] = value
if hasattr(self, 'clean_%s' % name): # 反射
value = getattr(self, 'clean_%s' % name)()
self.cleaned_data[name] = value
except ValidationError as e:
self.add_error(name, e)
2.self._clean_form()
def _clean_form(self):
try:
cleaned_data = self.clean()
except ValidationError as e:
self.add_error(None, e)
else:
if cleaned_data is not None:
self.cleaned_data = cleaned_data
3.self._post_clean()
注:在面向对象中封装特性里变量名前加括号是告诉我们不要直接访问(隐藏)
涉及内容:面向对象 反射判断是否存在该属性与获取该属性
modelform组件
1.modelform组件是form组件的优化版本
class MyModelForm(forms.ModelForm):
class Meta:
model = models.User
fields = '__all__'
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
posted on
浙公网安备 33010602011771号