水痕 2019-10-29
目录
只需要会使用即可。
在Django项目下新建utils文件夹,新建一个py文件,放入封装好的分页器代码。
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)
class Books(View): def get(self, request): book_queryset = models.Book.objects.all() # 获取所有书籍对象 current_page = request.GET.get('page', 1) # 获得当前页码,如果没有就为1 book_count = book_queryset.count() # 获取数据总条数 # 1 分页器类实例化出对象 page_obj = Pagination(per_page_num=12, current_page=current_page, all_count=book_count) # 2 对数据进行切片操作,每页展示 page_queryset = book_queryset[page_obj.start:page_obj.end] return render(request, 'Books.html', locals())
{% for foo in page_queryset %} <p>{{ foo.title }}</p> {% endfor %} {{ page_obj.page_html|safe }}
校验数据通常是前后端都校验,但是前端校验可有可无,后端必须校验
注册功能需求: 用户输入的用户名种不能包含‘虫合’,不可小于三位,不可大于八位 如果包含了,就提示用户---》太暴力了 用户输入的密码,不可小于三位,不可大于八位 太短太长都提示 搭建步骤: 1.搭建前端页面 >>> 渲染页面 2.获取前端用户提交的数据校验 >>> 校验数据 3.对数据的校验的结果 展示到前端页面给用户查看 >>> 展示错误信息 form组件能够自动帮你完成上面的三件事
# 1 自己先写一个类 # 像创建表一样规定了各个输入框需要遵守的规则,以及违反对应规则会抛出的错误 class Myform(forms.Form): username = forms.CharField(max_length=8, min_length=3, error_messages={ 'min_length': '你太短了', 'max_length': '你太长了', 'required': '不可为空' }, initial='我是初始值', widget= widgets.TextInput(attrs={'class':'form-control others'})#为这个input标签添加了一个类,用attr={}的方式设置 #widget可以改变input框的type属性值 pwd = forms.CharField(max_length=8, min_length=3, error_messages={ 'min_length': '你太短了', 'max_length': '你太长了', 'required': '不可为空' }, initial='我是初始值',widget=widgets.PasswordInput()) #2 后端代码 def reg(request): form_obj = Myform()#将自己写的类实例化出一个对象,若请求方式为get则不通过校验,直接将form_obj传到前端页面,提供渲染页面的功能 if request.method=='POST': #由于request.POST本身就是个大字典,直接扔进去做校验 form_obj=Myform(request.POST) if form_obj.is_valid(): #is_valid判断是否所有键值对都满足规则,只有都满足时is_valid才为真 return HttpResponse('合法') return render(request,'reg.html',locals()) #3 前端代码 <form action="" method="post" novalidate> #novalidate是告诉浏览器无需在浏览器做校验 {% for foo in form_obj %} <p>{{ foo.label }}: {{ foo }}</p> <span style="color: red">{{ foo.errors.0 }}</span> #foo.errors拿到的是列表的错误信息,取第一个直接拿出错误信息,如没有错误则为空 {% endfor %} <input type="submit"> #局部钩子 校验用户输入的用户名种不得包含‘虫合’(写在自定的Myform类中) def clean_username(self): username = self.cleaned_data.get('username') #cleaned_data是一个字典,如果键值对经过之前的校验并通过了,就会放在这里面 #与cleaned_data相反的是errors,也是字典,保存的是校验不通过的字段以及原因 if '虫合' in username: # 给username字段下面提示错误信息 self.add_error('username', '太暴力了') return self.cleaned_data #return username #全局钩子 校验用户名与密码不得相同 def clean(self): username=self.cleaned_data.get('username') pwd=self.cleaned_data.get('pwd') if pwd==username: self.add_error('pwd','密码不得与用户名相同') return self.cleaned_data #return pwd
如何渲染页面 1.forms组件只会帮你渲染获取用户输入(输入,选择,下拉框...)的标签 提交按钮需要你自己手动写 <p>三种渲染前端页面的方式</p> <p>第一种渲染前端页面的方式:封装程度太高了 标签样式及参数不方便调整 可扩展性差(不推荐使用) {{ form_obj.as_p }} {{ form_obj.as_ul }} </p> <p>第二种渲染页面的方式:扩展性较高 不足之处在于 需要你手写的代码量比较多(不推荐使用)</p> <p> {{ form_obj.username.label }}{{ form_obj.username }} </p> <p> {{ form_obj.password.label }}{{ form_obj.password }} </p> <p> {{ form_obj.email.label }}{{ form_obj.email }} </p> <p>第三种渲染前端页面的方式:代码量和扩展性都很高(推荐使用)</p> {% for foo in form_obj %} <p>{{ foo.label }}{{ foo }}</p> {% endfor %}
每个字段 还支持正则校验 from django import forms from django.forms import Form from django.core.validators import RegexValidator class MyForm(Form): user = forms.CharField( validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')], )