分页
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表单校验组件
因为校验的安全性,前端能够没有校验,可是后端必须校验html
自定义组件
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,能够取消上面的功能django
<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>
后端app
能够经过这个简便的实现数据提交,form的内容还在,由于obj记录下来数据了函数
其实后端返回的都是obj对象,只是最开始的那个是没有数据的,因此主要起渲染界面用ui
将数据传上去后,生成的那个对象是带数据的,因此会携带错误信息并渲染到前端,两个obj是不一样的url
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() # )