zoukankan      html  css  js  c++  java
  • Form组件

    手动实现登录校验的功能

    前端代码

    <form action="" method="post">
        {% csrf_token %}
        <p>username:<input type="text" name="username" value="{{ username }}"><span>{{ back_dic.username }}</span></p>
        <p>password:<input type="text" name="password" value="{{ password }}"><span>{{ back_dic.password }}</span></p>
        <p><input type="submit"></p>
    </form>
    前端

    后端代码

    def register(request):
        back_dic = {
            "username":"",
            "password":""
        }
        username = ""
        password = ""
        if request.method == 'POST':
            username = request.POST.get("username")
            password = request.POST.get("password")
            if "666"in username:        # 不符合,就把提示信息加入到字典中,在页面中相应的地方渲染
                back_dic["username"] = "喊6剁手"
            if len(password) < 3:
                back_dic["password"] = "密码太短"
    
        return render(request, "register.html",locals())
    # 除了大字典传参渲染页面之外, locals()也可以传参渲染,并且locals()会把定义的变量全部传过去
    后端

    上述代码我们一共实现三个功能

      1. 渲染页面

      2. 对数据进行校验

      3. 展示提示信息

    form组件实现的功能

    form组件主要也是帮我们实现上面三个功能

    1. 对数据进行校验

    数据校验分为前端校验和后端校验两种,前端校验可以不做,后端校验必须做

    因为前端很脆弱,别人可容易就会越过你的校验,如果我们后端不做校验

    就会很危险,后端校验如下

    # 使用form组件的第一步就是需要我们自己写一个类去继承forms.Form
    from django import forms
    class MyForm(forms.Form):
        username = forms.CharField(max_length=6, label="用户名")
                                # max_length表示限制条件,  label表示文本信息
        password = forms.CharField(max_length=6, min_length=3, label="密码", error_messages={"min_length":"密码太短"})
    
    def register(request):
        # 生成一个form对象
        form_obj = MyForm()
    
        if request.method == 'POST':
            # 前端传过来数据之后
            # 1. 给form组件传参,字典的形式
            form_obj = MyForm(request.POST)
            # 2.判断数据是否全部合法 is_valid()
            print(form_obj.is_valid())  # is_valid() 方法会校验你传入的数据是否符合定义的限制
                                        # 只要有一个不符合就会返回False
            # 3. 查看所有校验通过的数据cleaned_data
            print(form_obj.cleaned_data)
            # 4. 查看所有没通过的数据及其报错信息errors
            print(form_obj.errors)
        return render(request, "register.html", locals())

    2. 渲染页面

    渲染页面主要有三种方式

    第一种渲染标签方式(本地)

    {{ form_obj.as_p }}

    直接通过forms对象点as_p 就可以生成所有被p包裹的标签,

    如果点as_ul,就会生成被li包裹的标签,并且在展示时,默认会把label标签的首字母大写

    但是这种方法的封装程度太高,不方便我们后期添加样式,所以基本上作本地测试用

    第二种渲染标签方式(可扩展性高)

    <p>{{ form_obj.username.label }}{{ form_obj.username }}</p>
    <p>{{ form_obj.password.label }}{{ form_obj.password }}</p>

    我们自己定义标签,通过forms对象点出单独的标签,这种方式的扩展性高

    但是如果我们forms对象的字段比较多的话,一个一个点比较麻烦

    第三种渲染标签的方式(常用)

    {% for foo in form_obj %}
        {{ foo.label }}{{ foo }}
    {% endfor %}

    我们可以循环forms对象,得到是每一个字段对应的标签,这样我们就可以

    通过点语法得到我们想要的标签(扩展性高且不用写太多代码)

    3. 展示错误信息

    当我们渲染完标签之后,我们会发现当我们输入错误信息的时候,浏览器端

    会提示我们报错信息,如下

    这种提示错误信息的方式其实是forms组件在前端做了判断,并展示出报错信息

    前面我们也提到过,既然后端进行了数据校验,那么我们可不可以自定义提示信息呢

    如果我们想展示后端错误信息,那首先需要让前端停止校验

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

    novalidate的意思就是让前端停止校验

    首选我们需要在每个字段中添加错误条件及其对应的提示 error_messages

    password = forms.CharField(max_length=6, min_length=3, label="密码", 
                               error_messages={
                                   "min_length":"密码太短",
                                   "max_length":"密码太长"
                                               })

    然后我们在前端,可以通过.errors拿到报错信息的一个列表,索引0取出信息

    {% for foo in form_obj %}
        <p>{{ foo.label }}{{ foo }} {{ foo.errors }}</p>
    {% endfor %}

    这样就可以展示出我们自己的提示信息了

    还有一点之前忘了补充:

    那就是如果我们不用forms组件去提示错误信息,那也会把用户之前输入的

    信息全部刷新掉,这种体验是非常差的,而我们的forms组件则会保留之前的信息

    form组件的hook函数(钩子函数)

    上面展示的错误提示都是一些系统里面自带的校验规则,例如最大、最小长度

    那我们想自己定义一些规则,例如用户名不能包含666,这就需要用到钩子函数

    钩子函数分为两种,局部钩子与全局钩子

    局部钩子

    局部钩子只能对单个字段进行二次校验

    def clean_username(self):   # 局部钩子通过clean_字段名 定义, 只要在上面出现过的字段,在这都会有提示
        username = self.cleaned_data.get("username")  # 然后我们取值需要从校验成功这里面取值
        if "666" in username: # 进行判断,错误就通过add_error添加到错误信息中
            self.add_error("username", "不能包含666") # add_error("字段名", "错误信息")
        return username # 为了健壮性, 就把username返出去

    全局钩子

    全局钩子可以对多个字段联合起来校验

    def clean(self): # 全局钩子直接通过clean来定义
        password = self.cleaned_data.get("password")
        confirm_password = self.cleaned_data.get("confirm_password")
        if password != confirm_password:
            self.add_error("confirm_password", "两次密码不一致")
        return self.cleaned_data

    不管是全局钩子,还是局部钩子,都只有在通过了第一次校验之后,才会进入钩子函数

    forms组件类中一些其他字段及参数

    Field
        required=True,               是否允许为空
        widget=None,                 HTML插件
        label=None,                  用于生成Label标签或显示内容
        initial=None,                初始值
        help_text='',                帮助信息(在标签旁边显示)
        error_messages=None,         错误信息 {'required': '不能为空', 'invalid': '格式错误'}
        validators=[],               自定义验证规则
        localize=False,              是否支持本地化
        disabled=False,              是否可以编辑
        label_suffix=None            Label内容后缀
     
     
    CharField(Field)
        max_length=None,             最大长度
        min_length=None,             最小长度
        strip=True                   是否移除用户输入空白
     
    IntegerField(Field)
        max_value=None,              最大值
        min_value=None,              最小值
     
    FloatField(IntegerField)
        ...
     
    DecimalField(IntegerField)
        max_value=None,              最大值
        min_value=None,              最小值
        max_digits=None,             总长度
        decimal_places=None,         小数位长度
     
    BaseTemporalField(Field)
        input_formats=None          时间格式化   
     
    DateField(BaseTemporalField)    格式:2015-09-01
    TimeField(BaseTemporalField)    格式:11:12
    DateTimeField(BaseTemporalField)格式:2015-09-01 11:12
     
    DurationField(Field)            时间间隔:%d %H:%M:%S.%f
        ...
     
    RegexField(CharField)
        regex,                      自定制正则表达式
        max_length=None,            最大长度
        min_length=None,            最小长度
        error_message=None,         忽略,错误信息使用 error_messages={'invalid': '...'}
     
    EmailField(CharField)      
        ...
     
    FileField(Field)
        allow_empty_file=False     是否允许空文件
     
    ImageField(FileField)      
        ...
        注:需要PIL模块,pip3 install Pillow
        以上两个字典使用时,需要注意两点:
            - form表单中 enctype="multipart/form-data"
            - view函数中 obj = MyForm(request.POST, request.FILES)
     
    URLField(Field)
        ...
     
     
    BooleanField(Field)  
        ...
     
    NullBooleanField(BooleanField)
        ...
     
    ChoiceField(Field)
        ...
        choices=(),                选项,如:choices = ((0,'上海'),(1,'北京'),)
        required=True,             是否必填
        widget=None,               插件,默认select插件
        label=None,                Label内容
        initial=None,              初始值
        help_text='',              帮助提示
     
     
    ModelChoiceField(ChoiceField)
        ...                        django.forms.models.ModelChoiceField
        queryset,                  # 查询数据库中的数据
        empty_label="---------",   # 默认空显示内容
        to_field_name=None,        # HTML中value的值对应的字段
        limit_choices_to=None      # ModelForm中对queryset二次筛选
         
    ModelMultipleChoiceField(ModelChoiceField)
        ...                        django.forms.models.ModelMultipleChoiceField
     
     
         
    TypedChoiceField(ChoiceField)
        coerce = lambda val: val   对选中的值进行一次转换
        empty_value= ''            空值的默认值
     
    MultipleChoiceField(ChoiceField)
        ...
     
    TypedMultipleChoiceField(MultipleChoiceField)
        coerce = lambda val: val   对选中的每一个值进行一次转换
        empty_value= ''            空值的默认值
     
    ComboField(Field)
        fields=()                  使用多个验证,如下:即验证最大长度20,又验证邮箱格式
                                   fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
     
    MultiValueField(Field)
        PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用
     
    SplitDateTimeField(MultiValueField)
        input_date_formats=None,   格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']
        input_time_formats=None    格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
     
    FilePathField(ChoiceField)     文件选项,目录下文件显示在页面中
        path,                      文件夹路径
        match=None,                正则匹配
        recursive=False,           递归下面的文件夹
        allow_files=True,          允许文件
        allow_folders=False,       允许文件夹
        required=True,
        widget=None,
        label=None,
        initial=None,
        help_text=''
     
    GenericIPAddressField
        protocol='both',           both,ipv4,ipv6支持的IP格式
        unpack_ipv4=False          解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用
     
    SlugField(CharField)           数字,字母,下划线,减号(连字符)
        ...
     
    UUIDField(CharField)           uuid类型
    
    
    Django Form内置字段
    字段及参数

    具体内容及使用方法

  • 相关阅读:
    npm私服包管理-发布
    搭建npm私服
    vue.js框架搭建
    基于cropper实现图片上传,剪切,下载
    base64转图片
    获取file的路径
    如何制定好测试策略(一)
    让测试团队慢慢死去!-有同感,转载
    2016-2016自动化测试的趋势
    2016-安全性测试
  • 原文地址:https://www.cnblogs.com/hesujian/p/11229488.html
Copyright © 2011-2022 走看看