1.数据校验功能
# 提前准备好form类型 from django import forms class MyForm(form.Form) name = forms.CharField(max_length=8,min_length=3) # 名字最长8个字符最短3个字符 age = forms.IntegerField(max_value=150,min_value=0) # 年龄最大150 最低0 email = forms.EmailField() # 邮箱必须符合邮箱格式@符号form组件支持提前设置各种校验规则之后自动校验:
∙ " role="presentation" style="position: relative;"> 自定义一个继承form.Form的类
∙ " role="presentation" style="position: relative;"> 实例化类,传入前端
∙ " role="presentation" style="position: relative;"> 获得返回数据进行判断obj.is_valid()
∙ " role="presentation" style="position: relative;"> 自定输入的错误类型返回给前端校验用户输入的信息是否符合表字段的参数 :
# 1.传递待校验的数据 form_obj = views.MyForm({'name':'haha','age':20,'email':'qqcom'}) # 2.判断所有的数据是否符合校验 form.obj.is_valid() # 3.获取符合校验规则的数据:{'name':'haha','age':20} form_obj.cleaned_data # 4.查看不符合校验规则的数据及错误原因:{'email': ['Enter a valid email address.']} form_obj.errorsps:form类中编写的字段默认都是必填的如果没有传入足够对应的数据则肯定通不过校验,但是如果多传入了字段则不影响校验多出来的字段不会参与校验直接忽略
2.form组件渲染标签
form组件支持直接渲染获取用户数据的各种标签,并有三种方式每一种方式都有自己的特点
方式一:
{{ form_obj.as_p }} {{ form_obj.as_table }} {{ form_obj.as_ul }} ''' 优点:速度快 代码少 缺点:封装程度高 扩展性差 '''方式二:
{{ form_obj.name.lable }} {{ form_obj.name }} ''' 优点:扩展性好 缺点:编写困难 封装程度低 '''方式三:
{% for form in form_obj %}{{ form.label }}{{ form }}
{% endfor %} ''' 推荐使用的方法 代码书写简单 并且可扩展性强 类以外的所有标签都不会自动渲染 需要自己编写 '''3.form展示提示信息
展示当校验不通过的时候提示的信息,但是浏览器会提前帮你走它自带的校验,前端校验又形同虚设所以我们得先取消浏览器的自动校验再设置form提示信息
<for action="" method="post" novalidate> {% for form in form_obj %} <p> {{ form.label }}{{ form }} <span style = "color:red;">{{ form.errors.0 }}span> p> {% endfor %} <input type="submit" value="提交">
# 在视图层 def func(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,'func.html',locals())4.form组件重要字段参数
创建Form类时主要涉及到字段和插件,字段用于对用户请求数据的验证插件用于自动生成HTML
CharField(Field) max_length=None 最大长度 min_length=None 最小长度 strip=True 去除用户输入空白 IntegerField(Field) max_value=None 最大值 min_value=None 最小值 Field required 是否允许为空 label 字段注释 error_messages 错误信息{'':''} regex 自定义正则表达式 initial 默认值
真正的数据校验应该是要结合数据库,我们通过利用钩子函数来校验用户注册登陆功能来理解钩子函数
# 局部钩子:当注册用户名为haha是提示用户以注册 def clean_name(self): name = self.cleaned_data.get('name') res = models.User.objects.filter(name=name).first() if res: return self.add_error('haha','用户以被注册') return name # 全局钩子:校验第一次密码与第二次密码是否一致 # confirm_pwd为二次输入字段 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
通过名字就大致可以知道这个组件的多功能就是把model和form组合起来,更加优化了form使其用起来更简单功能更强大
# 使用modelform组件 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
现在有一个需求当访问一个页面的时候立刻创建几万条数据并展示到这个页面上,如果这个需求直接用models加for循环来实现的时候还没有创建一半数据库就会奔溃并且加载速度很慢很慢
针对大批量数据的创建与修改用普通的方式是不行的models给我们准备了特定的方式
∙ " role="presentation" style="position: relative;"> 批量创建数据:bulk_create()
∙ " role="presentation" style="position: relative;"> 批量修改数据:bulk_update()
def index(request): book_list = [] for i in range(100000): book_obj = models.Book(title=f'第{i}本书') book_list.append(book_obj) models.Book.objects.bulk_create(book_list) book_query = models.Book.objects.all() return render(request,'bookList.html',locals())
当需要展示大量数据的时候如果同时一下子全部加载到页面上给人的观看感肯定不佳,同时也有卡死的现象,所以我们要用到分页指定一个页面展示几条这样就简介清楚
∙ " role="presentation" style="position: relative;"> 自定义分页器封装代码需要用的时候直接复制即可,但是其中原理最好能掌握
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: 最多显示的页码个数 """ 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(''' ''') first_page = '- 首页
' % (1) page_html_list.append(first_page) if self.current_page <= 1: prev_page = '- 上一页
' else: prev_page = '- 上一页
' % (self.current_page - 1,) page_html_list.append(prev_page) for i in range(pager_start, pager_end): if i == self.current_page: temp = '- %s
' % (i, i,) else: temp = '- %s
' % (i, i,) page_html_list.append(temp) if self.current_page >= self.all_pager: next_page = '- 下一页
' else: next_page = '- 下一页
' % (self.current_page + 1,) page_html_list.append(next_page) last_page = '- 尾页
' % (self.all_pager,) page_html_list.append(last_page) # 尾部添加标签 page_html_list.append(''' ''') return ''.join(page_html_list)
∙ " role="presentation" style="position: relative;"> 在后端中使用
def get_book(request): book_list = models.Book.objects.all() current_page = request.GET.get("page",1) all_count = book_list.count() page_obj = Pagination(current_page=current_page,all_count=all_count,per_page_num=10) page_queryset = book_list[page_obj.start:page_obj.end] return render(request,'booklist.html',locals())
∙ " role="presentation" style="position: relative;"> 在前端中使用
<div class="container"> <div class="row"> <div class="col-md-8 col-md-offset-2"> {% for book in page_queryset %} <p>{{ book.title }}p> {% endfor %} {{ page_obj.page_html|safe }} div> div> div>ps:有空时会补上分页具体的逻辑思想与用到的知识点分析