zoukankan      html  css  js  c++  java
  • day68——使用自定义分页器、Forms组件功能与应用

    自定义分页器的拷贝与使用

    自定义分页器

    当我们需要用到非django内置的第三方功能或组件的时候,由于拷过来的东西不能瞎放,我们一般会创建一个名为utils的文件夹来存放。该文件夹可以在django根目录下创建;在分组开发每个应用需要不同组件的时候,也可以在每个应用下分别创建utils的文件夹,具体根据实际情况来定。

    注意:

    上述自定义的分页器是基于bootstrap样式来了,使用时页面需要导入bootstrap。

    后端

    代码很简单,将分页器代码拷贝到utils文件夹下需要使用时导入Pagination即可;给类传值生成对象,利用分区器对象的start和end属性对总数据进行切片获取当前页需要展示的数据,然后将数据传入html页面展示。

    book_queryset = models.Book.objects.all()
    current_page = request.GET.get('page',1)
    all_count = book_queryset.count()
    # 1 传值生成对象
    page_obj = Pagination(current_page=current_page,all_count=all_count)
    # 2 直接对总数据进行切片操作
    page_queryset = book_queryset[page_obj.start:page_obj.end]
    # 3 将page_queryset传递到页面 替换之前的book_queryset
    
    

    前端

    自定义分页器代码中已经封装好了bootstrap分页器的样式,分页器用模版语法直接.page_html使用即可,无需自己渲染分页器,需加上|safe进行转义,当然也可以在后端完成转义。

    # 前端
    {% for book_obj in page_queryset %}
        <p>{{ book_obj.title }}</p>
        <nav aria-label="Page navigation">
    </nav>
    {% endfor %}
    {#利用自定义分页器直接显示分页器样式#}
    {{ page_obj.page_html|safe }}
      
    

    Forms组件

    我们先写一个简单的注册功能来一步步引出Forms组件。

    注册功能需求:

    前端页面获取用户名和密码,利用form表单提交数据,后端接收到数据进行数据的校验,看是否满足用户名不能含有字符'666'以及密码不能小于三位的条件,如果不满足条件,则在前端页面展示错误信息。

    后端:

    def id_check(request):
        msg_dict = {'username': '', 'password': ''}  # 定义一个值是空字符串的字典
        if request.method == 'POST':
            username = request.POST.get('username')  # 获取用户的输入的信息
            password = request.POST.get('password')
            if '666' in username:  # 对数据进行校验,有错则给字典对应的字段添加错误信息
                msg_dict['username'] = '不能做一条只会喊6的咸鱼'
            if len(password) < 3:
                msg_dict['password'] = '密码还是长点安全'
        return render(request, 'id_check.html', locals())
        """无论是get请求还是post请求都能给页面返回错误信息字典,post请求来的时候字段可能有值。"""
    

    前端:

    <form action="" method="post">
        <p>用户名:
            <input type="text" name="username">
    	   {#span便签的大小取决于文本,只有在字典有错误信息时才能取到值进行展示,否则span标签隐藏不展示#}
            <span style="color: red">{{ msg_dict.username }}</span></p>
        <p>密码:
            <input type="text" name="password">
            <span style="color: red">{{ msg_dict.password }}</span></p>
        <p><input type="submit"></p>
    </form>
    

    实现该注册功能我们的总共干了三件事:

    • 手动书写前端获取用户数据的html代码——>渲染html代码
    • 后端对用户数据进行校验——>校验数据
    • 对不符合要求的数据进行前端提示——>展示提示信息

    渲染html、代码校验数据、展示提示信息Forms组件都可以实现,无需我们书写繁杂的代码。

    后端校验的重要性

    数据的校验可分为前端数据校验和后端的数据校验;前端的数据校验可有可无,因为可以在浏览器内进行修改,而后端校验才是必须要有了,保护服务端数据的安全。

    Forms组件基本使用

    需要先充django中导入forms模块,书写的时候跟写模型表类似。

    from django import forms
    class MyForm(forms.Form):
        # username字符串类型最小3位最大8位
        username = forms.CharField(min_length=3,max_length=8)
        # password字符串类型最小3位最大8位
        password = forms.CharField(min_length=3,max_length=8)
        # email字段必须符合邮箱格式  xxx@xx.com
        email = forms.EmailField()
    

    校验数据:

    之前我们学习了测试脚本的创建,但其实pycharm已经准备好一个测试环境python console,在charm页面的正下方打开就可以测试代码,在创建数据时,可以帮我们每个字段是否合法。

    from app01 import views
    
    # 1 将带校验的数据组织成字典的形式传入即可
    form_obj = views.MyForm({'username':'jason',
                             'password':'123',
                             'email':'123'})
    
    # 2 判断数据是否合法,注意该方法只有在所有的数据全部合法的情况下才会返回True
    form_obj.is_valid()
    # False
    
    # 3 查看所有校验通过的数据
    form_obj.cleaned_data
    # {'username': 'jason', 'password': '123'}
    
    # 4 查看所有不符合校验规则以及不符合的原因
    form_obj.errors
    """{
      'email': ['Enter a valid email address.']
    }"""
    
    # 5 校验数据只校验类中出现的字段 多传不影响 多传的字段直接忽略
    form_obj = views.MyForm({'username':'jason',
                             'password':'123',
                             'email':'123@qq.com',
                             'hobby':'study'})
    form_obj.is_valid()
    # True
    res4.errors
    # {}
    
    # 6 校验数据 默认情况下 类里面所有的字段都必须传值
    form_obj = views.MyForms({'username':'jason',
                              'password':'111'})
    print(res4.is_valid())
    # True
    form_obj.errors
    # {'email': ['This field is required.']}
    """
    也就意味着校验数据的时候 默认情况下数据可以多传但是绝不可能少传
    """
    

    渲染标签

    form组件会自动渲染获取用户输入的标签(input radio checkbox select textarea ...)

    但是它不会渲染提交标签,需要我们自己书写代码渲染。

    后端:

    def randering_label(request):
        form_obj = MyForms()  # 先生成空对象
    	return render(request,'ren_label.html')  # 直接将空对象传给页面    
    

    前端渲染:

    • 方式一:

      <body>
          {{ form_obj.as_p }}  <!--每个标签单独占一行-->
          {{ form_obj.as_ul }}  <!--每个标签单独占一行,竖向无序排列-->
          {{ form_obj.as_table }}  <!--标签横向按表格的形式排列-->
      </body>
      

      第一种方式书写的代码最少,最为方便,但是封装程度太高,不利于后期的扩展,一般只在本地测试使用。

    • 方式二:

      逐个标签进行渲染,扩展性强,但是需要书写的代码太多。如果标签过多逐个书写太麻烦,一般情况不使用这种渲染方式。

      <body>
      {{ form_obj.username.label }}:{{ form_obj.username }}
      {{ form_obj.password.label }};{{ form_obj.password }} 
      </body>
      
      

      label属性默认展示的是类中定义的字段首字母大写的形式,还可以自己修改,在对应字段对象指定label参数即可...max_length=8,label='用户名')

    • 方式三:

      利用循环的方式减少代码的书写,并且有一定的扩展性,推荐使用

      <body>
      {% for form in form_obj %}
      	<p>{{ form.label }}:{{ form }}</p>  <!--用p标签包裹将每个标签单行展示-->
      {% endfor %}
      </body>
      

    展示提示信息

    取消浏览器校验数据novalidate

    我们给页面传一个空的form对象,后端不进行数据的校验时;在输入框中输入不合法的数据提交数据后,输入框向下弹出样式很好看的提示信息,这其实是浏览器帮我做的校验,但这种校验弱不禁风,浏览器内修改前端代码就会失效。

    def ren_label(request):
        form_obj = MyForms()
        return render(request, 'ren_label.html', locals())
    

    浏览器对该字段的校验代码:

    <input type="text" name="username" maxlength="6" minlength="3" required="" id="id_username">
    

    我们右键检查在浏览器内将该校验条件修改:

    <input type="text" name="username" maxlength="6" minlength="2" required="" id="id_username">
    

    再次提交用户名'66'校验就失效了

    这也验证了前端校验的不可靠性和后端校验的重要性

    可在前端form便签内设置浏览器不进行校验

    <form action="" method="post" novalidate>
    

    form组件展示提示信息

    后端:

    def check_data(request):
        # 1 先产生一个空的form对象
        form_obj = MyForm()
        # 2 定义一个空字字典,如果数据通过校验,给字典添加“注册成功”提示信息
        back_msg = {'success': ''}
        if request.method == 'POST':
            # 3 可将request.POST看是一个字典当参数传入
             form_obj = MyForm(request.POST)
            # 4.校验数据
            if form_obj.is_valid():
                back_msg['success'] = '注册成功'
        return render(request, 'ren_label.html', locals())  
    """无论是GET请求还是POST请求都能返回一个form对象给页面,
       POST请求来的时候对象可能不为空"""
    

    注意:为了保证html页面不管什么情况下都能有一个form对象来渲染标签,get请求和post传给html页面对象变量名必须一样。

    前端:

    <body>
    <form action="" method="post" novalidate>
        <h1 class="text-center">注册页面</h1>
        {% for form in form_obj %}
        <p>{{ form.label }}:{{ form }}<span style="color:red">{{ form.errors.0 }}</span></p>
        {% endfor %}
        <input type="submit" class="btn-success btn-lg">
        <span style="font-size: large;color:green" class="span">{{ back_msg.success }}</span>
    </form>
    <script>function clean_span() {
           $('.span') .remove()
        }
        setInterval(clean_span, 2000)
    </script>
    </body>
    

    form.errors.0 :错误信息可能为多个所以是一个列表,在展示的时候会被渲染成无序列表的形式,按索引取值取消这种渲染。

    数据校验不通过展示提示信息:

    通过校验提示注册成功:

    forms组件会保存你上次的数据,让你基于之前的结果进行修改,更加的人性化。

    自定义错误信息:

    class MyForm(forms.Form):
        # username字符串类型最小3位最大8位
        username = forms.CharField(min_length=3,max_length=8,label='用户名',
                                   error_messages={
                                       'min_length':'用户名最少3位',
                                       'max_length':'用户名最大8位',
                                       'required':"用户名不能为空"
                                   }
        # email字段必须符合邮箱格式  xxx@xx.com
        email = forms.EmailField(label='邮箱',
                                 error_messages={
                                     'invalid':'邮箱格式不正确',
                                     'required': "邮箱不能为空"
                                 }
                                 )                       
    

    钩子函数(HOOK):

    在特定的节点自动触发完成响应操作,钩子函数相当于forms组件的第二道数据校验关卡,能够支持我们自定义校验规则

    forms组件两类钩子函数:

    • 局部钩子函数

      当你需要给单个字段增加校验规则的时候可以使用

      eg:对用户名进行校验,里面不能含有字符'6';单个字段username的校验用局部钩子函数

    • 全局钩子函数

      当你需要给多个字段增加校验规则的时候可以使用

      eg:核对密码和确认密码是否一致;两个字段校验数据用全局钩子函数

    # 钩子函数在类里面书写方法即可
    class MyForm(forms.Form):
    	# 1 局部钩子函数
        def clean_username(self):
            # 获取到用户名
            username = self.cleaned_data.get('username')
            if '6' in username:
                self.add_error('username', '光喊6是不行滴!')
            # 将钩子函数钩去出来数据再放回去    
            return username
        
        
    	# 2 全部钩子函数
        def clean(self):
            password = self.cleaned_data.get('password')
            conform_password = self.cleaned_data.get('conform_password')
            if conform_password != password:
                self.add_error('conform_password', '密码不一致')
            # 全局钩子函数将所有数据再放回去      
            return self.cleaned_data
    

    对数据内容进行二次校验:

    forms组件其他参数及补充知识点:

    • label(汉字/英文)——>字段名(英文则首字母大写)

    • error_messages({'字段校验条件':'错误信息',})——>自定义报错信息

    • required(True/False)——>控制字段是否必填

    • widget——>为标签修改样式

      widget=forms.widgets.PasswordInput(attrs={'class':'form-control c1 c2'})  # 具有bootstrap样式的密文输入框
      
      widget=forms.widgets.Select() # 下拉选择框
      
    • 第一道关卡里面还支持正则校验:

      validators=[
                  RegexValidator(r'^[0-9]+$', '请输入数字'),
                  RegexValidator(r'^159[0-9]+$', '数字必须以159开头')
              ]
      

    其他类型渲染

    	# radio
        gender = forms.ChoiceField(
            choices=((1, "男"), (2, "女"), (3, "保密")),
            label="性别",
            initial=3,
            widget=forms.widgets.RadioSelect()
        )
        
        # select
        hobby = forms.ChoiceField(
            choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
            label="爱好",
            initial=3,
            widget=forms.widgets.Select()
        )
        
        # 多选
        hobby1 = forms.MultipleChoiceField(
            choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
            label="爱好",
            initial=[1, 3],
            widget=forms.widgets.SelectMultiple()
        )
        
        # 单选checkbox
        keep = forms.ChoiceField(
            label="是否记住密码",
            initial="checked",
            widget=forms.widgets.CheckboxInput()
        )
        
        # 多选checkbox
        hobby2 = forms.MultipleChoiceField(
            choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
            label="爱好",
            initial=[1, 3],
            widget=forms.widgets.CheckboxSelectMultiple()
        )
    

    创建字段时forms跟有Choice表示该字段为可选类型,MultipleChoice表示多选,widgets后面点什么就是什么类型的输入标签,...select:表示单选,...SelectMultiple:表示多选;标签类型的单选和多选必须跟字段匹配。

  • 相关阅读:
    Java学习:线程实现方式
    Java学习:异常的概念
    HDFS 其他命令---fsck
    Linux 常用命令
    Linux命令注释—HDFS运维
    大数据简介
    FusionInsight大数据开发---Oozie应用开发
    FusionInsight大数据开发---Flume应用开发
    FusionInsight大数据开发---Streaming应用开发
    FusionInsight大数据开发---Redis应用开发
  • 原文地址:https://www.cnblogs.com/zhangtieshan/p/13054318.html
Copyright © 2011-2022 走看看