Django-分页-form数据校验
分页
view层
def fenye(request):
all_data = models.AuthorDetail.objects.all()
current_page = request.GET.get('page',1)
count = all_data.count()
page_obj = Pagination(current_page=current_page,all_count=count)
data = all_data[page_obj.start:page_obj.end]
return render(request,'fenye.html',locals())
模板层
{% for a in data %}
<p>{{ a.addr }}</p>
{% endfor %}
{{ page_obj.page_html|safe }}
自定义分页器
class Pagination(object):
def __init__(self, current_page, all_count, per_page_num=10, 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)
form表单校验组件
由于校验的安全性,前端可以没有校验,但是后端必须校验
自定义组件
from django import forms
from app01 import models
class myzx(forms.Form):
username = forms.CharField(min_length=3, max_length=8, label='用户名',
error_messages={
'min_length': '用户名不能少于三位',
'max_length': '用户名不能大于八位',
'required': '用户名不能为空',
}, widget=forms.widgets.TextInput(attrs={'class': 'form-control'})
)
password = forms.CharField(min_length=3, max_length=8, label='密码',
error_messages={
'min_length': '密码不能少于三位',
'max_length': '密码不能大于八位',
'required': '密码不能为空',
}, widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'})
)
confirm_password = forms.CharField(min_length=3, max_length=8, label='确认密码',
error_messages={
'min_length': '确认密码不能少于三位',
'max_length': '确认密码不能大于八位',
'required': '确认密码不能为空',
}, widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'})
)
email = forms.EmailField(
label='邮箱',
error_messages={
'required': '邮箱不能为空',
'invalid': '邮箱格式不正确'
}, widget=forms.widgets.EmailInput(attrs={"class": 'form-control'})
)
前端表单可以自己写,也可以使用组件提供的
obj为自己定义的组件对象
<form method="POST">
<p>{{ obj.username }}</p>
<p>{{ obj.confirm_password }}</p>
<p>{{ obj.confirm_password }}</p>
<p>{{ obj.email }}</p>
<input type="submit" value="提交">
</form>
但是这样渲染,会默认加上前端的校验,但是加在前端是不安全的,所以不采用
<form method="POST">
<p><input type="text" name="username" class="form-control" maxlength="8" minlength="3" required="" id="id_username"></p>
<p><input type="password" name="confirm_password" class="form-control" maxlength="8" minlength="3" required="" id="id_confirm_password"></p>
<p><input type="password" name="confirm_password" class="form-control" maxlength="8" minlength="3" required="" id="id_confirm_password"></p>
<p><input type="email" name="email" class="form-control" required="" id="id_email"></p>
<input type="submit" value="提交">
</form>
要在form表单上加上novalidate,可以取消上面的功能
<form method="POST" novalidate>
校验上传的数据
#验证数据,获取验证结果对象
form_obj = myforms.MyRegForm(request.POST)
#判断是否全部验证成功
if form_obj.is_valid():
#用户提交的数据(字典形式的字段和字段值)
print(form_obj.cleaned_data)
else:
#用户提交错误的数据(错误信息为带前端样式的错误字段和错误描述信息)
#是一个字典,上面的打印信息时重写了str的原因
print(form_obj.errors)
半完成版小案例
前端
obj.errors.username.0,才能拿到不带前端标签,完整的错误描述
<form method="POST" novalidate>
<p>{{ obj.username.label }}{{ obj.username }}{{ obj.errors.username.0 }}</p>
<p>{{ obj.password.label }}{{ obj.password }}{{ obj.errors.password.0 }}</p>
<p>{{ obj.confirm_password.label }}{{ obj.confirm_password }}{{ obj.errors.confirm_password.0 }}</p>
<p>{{ obj.email.label }}{{ obj.email }}{{ obj.errors.email.0 }}</p>
<input type="submit" value="提交">
</form>
后端
可以通过这个简便的实现数据提交,form的内容还在,因为obj记录下来数据了
其实后端返回的都是obj对象,只是最开始的那个是没有数据的,所以主要起渲染界面用
将数据传上去后,生成的那个对象是带数据的,所以会携带错误信息并渲染到前端,两个obj是不同的
def text(request):
if request.method == 'GET':
obj = myforms.myzx()
return render(request,'zx.html',locals())
else:
obj = myforms.myzx(request.POST)
if obj.is_valid():
#打印验证成功的数据,即使数据有错也能打印,只打印验证通过的
print("验证成功",obj.cleaned_data)
return HttpResponse("数据校验成功")
else:
print("验证失败",obj.errors)
print(type(obj.errors))
return render(request,'zx.html',locals())
forms数据添加
在写forms约束的时候我们可以把字段名和models里面涉及的一样,这样的话,clean_data的数据字典就完全符合提交数据的要求了
#这样的话,数据就不用一条一条的取出来了,可以一次性提交数据
if obj.is_valid():
models.books.objects.create(**obj.cleaned_data)
forms数据编辑
编辑界面需要元数据的内容,那么就可以使用校验功能,然后把数据返回前台,而且数据是从数据库拿去的数据是不会有问题的,前端的样式和add差不多
def edit_user(request,nid):
if request.method == 'GET':
#获取数据
data = models.UserInfo.objects.filter(pk=nid).first()
#传给forms,因为它可以自动生成html
obj = UserForm({'username':data.username,'email':data.email})
return render(request,'edit_user.html',locals())
#else为修改数据的请求
else:
obj = UserForm(request.POST)
if obj.is_valid():
models.UserInfo.objects.filter(pk=id).update(**obj.cleaned_data)
return redirect('/users/')
else:
return render(request,'edit_user.html')
form字段大全
https://www.cnblogs.com/xiaoyuanqujing/articles/11753466.html
其中weight是生成前端代码的重要插件
返回参数为数字的单选框
zx = fields.ChoiceField(
choices = [(1,'钱'),(2,'权')]
)
动态获取元数据
一
刷新界面会执行这些代码,相当于重新去数据库取值
hobby = forms.IntegerField(
label='爱好',
widget=widgets.Select()
)
def __init__(self,*args,**kwargs):
super(myzx,self).__init__(*args,**kwargs)
print(models.Blog.objects.values_list('id','site_title'))
#注意这句要写后面,否则会被super覆盖掉值
self.fields['hobby'].widget.choices = models.Blog.objects.values_list('id','site_title')
二
from django.forms.models import ModelChoiceField
hobby2 = ModelChoiceField(
label='爱好2',
#是显示的数据部分,想要指定显示内容需要去重写models的str方法
queryset=models.Blog.objects.all(),
#只是显示value值,上传是使用的
to_field_name='id'
)
from前端html生成简写-高级
但是不推荐,自定制比较弱
{{obj.as_p}}
<ul>
{{obj.as_ul}}
</ul>
<table>
{{obj.as_table}}
</table>
前端字符串转标签
from django.utils safestring import mark_safe
txt = mark_safe(txt)
钩子函数
注意这些函数都要写在form类中
局部钩子函数
给部分字段加强校验
def clean_username(self):
username = self.cleaned_data.get('username')
if '88' in username:
self.add_error('username','名字不能包含88')
return username
全局钩子函数
针对多个字段校验使用全局钩子函数
def clean(self):
password = self.cleaned_data.get('password')
re_password = self.cleaned_data.get('re_password')
if not password == re_password:
self.add_error('re_password','密码不相等啊')
return self.cleaned_data
正则和其他表单数据提交
#
# phone = forms.CharField(label='手机号',validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')])
#
#
#
# """下面的是了解知识点 你只需要整理到你的博客中 到时候需要用 直接来拷贝即可"""
#
# gender = forms.ChoiceField(
# choices=((1, "男"), (2, "女"), (3, "保密")),
# label="性别",
# initial=3,
# widget=widgets.RadioSelect()
# )
#
#
#
#
# hobby = forms.ChoiceField(
# choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
# label="爱好",
# initial=3,
# widget=widgets.Select()
# )
#
# hobby1 = forms.MultipleChoiceField(
# choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
# label="爱好",
# initial=[1, 3],
# widget=widgets.SelectMultiple()
# )
#
# keep = forms.ChoiceField(
# label="是否记住密码",
# initial="checked",
# widget=forms.widgets.CheckboxInput()
# )
#
# hobby2 = forms.MultipleChoiceField(
# choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
# label="爱好",
# initial=[1, 3],
# widget=forms.widgets.CheckboxSelectMultiple()
# )
Django-分页-form数据校验的更多相关文章
- Django之form组件自动校验数据
目录 一.form介绍 二.普通方式手写注册功能 views.py register.html 三.使用form组件实现注册功能 views.py register2.html 四.pycharm的专 ...
- Django---form表单提交数据到数据库(普通方法+Django的form类)
目标: ①.初始form的简单应用 ②.使用Django的form组件完成新增一个帖子 方法一:普通方法 1.前端表单代码 <div> <form class="navba ...
- Laravel Form 表单的数据校验
例如,要使用手机号加验证码的方式提供登录网站的功能,那么在处理前端提交的 form 表单时,就不得不对提交的手机号及验证码做基本的数据校验. 手写规则,非常浪费时间.使用 laravel 内置的 va ...
- Django 分页查询并返回jsons数据,中文乱码解决方法
Django 分页查询并返回jsons数据,中文乱码解决方法 一.引子 Django 分页查询并返回 json ,需要将返回的 queryset 序列化, demo 如下: # coding=UTF- ...
- django 使用form组件提交数据之form表单提交
django的form组件可以减少后台在进行一些重复性的验证工作,极大降低开发效率. 最近遇到一个问题: 当使用form表单提交数据后,如果数据格式不符合后台定义的规则,需要重新在前端页面填写数据. ...
- Django之DRF源码分析(二)---数据校验部分
Django之DRF源码分析(二)---数据校验部分 is_valid() 源码 def is_valid(self, raise_exception=False): assert not hasat ...
- Django day26 HyperlinkedIdentityField,序列化组件的数据校验以及功能的(全局,局部)钩子函数,序列化组件的反序列化和保存
一:HyperlinkedIdentityField(用的很少):传三个参数:第一个路由名字,用来反向解析,第二个参数是要反向解析的参数值,第三个参数:有名分组的名字 -1 publish = ser ...
- Django--分页器(paginator)、Django的用户认证、Django的FORM表单
分页器(paginator) >>> from django.core.paginator import Paginator >>> objects = ['joh ...
- Django之 Form和ModelForm组件
01-Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用 ...
随机推荐
- mysql如何解除死锁状态
第一种: 1.查询是否锁表 show OPEN TABLES where In_use > 0; 2.查询进程(如果您有SUPER权限,您可以看到所有线程.否则,您只能看到您自己的线程) sho ...
- 指定路径批量将xls转换成csv
PS : 用到spire库,.net控制台应用程序 其实本来没打算写这个工具的,只是最近需要用到,手头上正好没有这样的工具,那么怎么办,写呗! 其实说白了就是省事,策划想怎么玩,把表把工具丢给他,省得 ...
- Oracle 相关操作SQL
SELECT l.session_id sid, s.serial#, l.locked_mode, l.oracle_username, s.user#,l.os_user_name,s.machi ...
- 一个自动管理项目的Makefile(C语言)
Linux 是所有嵌入式软件工程师绕不过去的坎, makefile 是在Linux系统中绕不过去的坎. 花了几天时间初步学习和了解了makefile 的作用以及功能,并且制作了一个通用型的makefi ...
- 【建站02】WordPress主题设置
大家好,我是帝哥.相信很多朋友看了我上一篇文章的介绍之后已经可以搭建自己的个人网站了,但是网站的功能和美观程度都还是有所欠缺的,现在呢,再给大家大概的介绍一些如何美化自己的网站,当然了,这个过程也是很 ...
- [考试反思]1010csp-s模拟测试67:摸索
嗯...所谓RP守恒? 仍然延续着好一场烂一场的规律. 虽说我也想打破这个规律,但是并不想在考烂之后打破这个规律.(因为下一场要考好???) 我也不知道我现在是什么状态,相较于前一阶段有所提升(第一鸡 ...
- 详谈Generator
Generator究竟有什么样的作用呢???? 他是ES6提出的一个解决异步问题方案 先看一段代码, 感受一下generator函数和普通函数的区别 function* test(){ yield 2 ...
- 使用Typescript重构axios(二十五)——文件上传下载进度监控
0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...
- NOIP模拟30B 活该
T1:没有判-1 T2:推出柿子之后手摸错了!,只交了一个表 T3....... 完戏!,就是活该!
- DHCP动态管理主机地址
步骤一:搭建环境 需要Windows 2008 R2 系统 (DHCP服务端)以及 CentOS7 系统客户机(DHCP客户机) 安装DHCP服务程序(这里提示读者,一般安装好CentOS系统之后, ...