• Django:form表单


    window.location.href = 域名
    #实现当前页面刷新
    

    1.小知识:箭头函数

    箭头函数,es6有,好处是不会重新绑定$(this)指向,会一直是最开始内容

    • 普通JS:

      <script>
              $(".btn-danger").click(function () {
                  console.log($(this));
                  $.ajax({
                      url:"/delpub/"+$(this).attr("del_id")+'/',
                      {#箭头函数,es6有,好处是不会重新绑定$(this)指向,#}
                      success:function(res){
                          console.log($(this));
                      }
      
                  })
              })
          </script>
      

    {#更改为箭头函数#}
    <script>
            $(".btn-danger").click(function () {
                console.log($(this));
                console.log($(this).attr("del_id"));{# 获取标签属性值 #}
                $.ajax({
                    url:"/delpub/"+$(this).attr("del_id")+'/',
                    {#箭头函数,es6有,好处是不会重新绑定$(this)指向,#}
                    success:(res) => {
                        console.log($(this));
                    }
    
                })
            })
        </script>
    

    2.Form介绍

    • form表单:在好多场景下都需要对用户的输入做校验,比如校验用户是否输入,输入的长度和格式等正不正确。如果用户输入的内容有错误就需要在页面上相应的位置显示对应的错误信息.。
    • form组件:
      • 生成页面可用HTML标签
      • 对用户信息提交的数据进行校验
      • 保留上次输入内容

    3.使用form组件实现简单注册界面

    1.定义form组件

    from django import forms
    #按照Django form组件先写一个类
    class RegForm(forms.Form):
        #form字段写的名称是什么,前端生成的input标签name就是什么,通过label可以更改label值
        name = forms.CharField(label="用户名" min_length=6)
        pwd = forms.CharField(label="密码" widget=forms.PasswordInput)
        #widget=forms.PasswordInput 作用是让密码成为密文
    
    #使用form组件实现注册
    def form_login(request):
        form_obj = RegForm()#实例化form对象
        if request.method == "POST":
            #from_obj有提交的数据
            form_obj = RegForm(data=request.POST)
            #调用form_obj校验数据的方式 ,返回值True或False
            #如果校验失败,form_obj会返回给页面:此时它的除了有数据还有错误信息
            if form_obj.is_valid():
                #.....插入数据代码
                return HttpResponse("注册成功")
            
        return render(request,"form_login.html",{"form_obj":form_obj})
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <!--会自动生成p标签,p标签有input框和label标签-->
        {{ form_obj.as_p }}
    </body>
    </html>
    
    • 显示效果:

    min_length=6 最小长度大于等于6

    widget=forms.PasswordInput 让输入框的内容成为密文

    {{ form_obj.errors }}返回当前所有错误

    form表单添加novalidate属性表示,前端不需要验证,为了让后端进行验证并且把信息返回回来
    <form action="" method="post" novalidate>
    	...
    </form>
    

    2.from组件功能总结

    1.生产input标签
    2.对提交的数据可以进行校验
    3.提交错误提示
    #不用form组件也可以实现上述方法,但过于麻烦,代码冗余长
    

    3.手动生成form表单

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
        <form action="" method="post" >
            {% csrf_token %}
            <div>
                <!--for="{{ form_obj.name.id_for_label }}表示for 指向 id_name-->
                <label for="{{ form_obj.name.id_for_label }}">{{ form_obj.name.label }}</label>
                <!--form_obj.name.error.0  为name对象第一个的错误-->
                {{ form_obj.name }}{{ form_obj.name.error.0 }}
            </div>
            <div>
                <label for="{{ form_obj.pwd.id_for_label }}">{{ form_obj.pwd.label }}</label>
                {{ form_obj.pwd }}{{ form_obj.pwd.errors.0 }}
            </div>
            <button>提交</button>
        </form>
    
    </body>
    </html>
    
    {{ form_obj.name }} 生成input框
    {{ form_obj.name.label }}  表示该字段中文提示
    {{ form_obj.name.id_for_label }} 表示该字段input框的id
    {{ form_obj.name.error}}  表示该字段所有的错误
    {{ form_obj.name.error.0}}  表示该字段第一个错误 
    

    4.Form常用字段与插件

    • ChoiceField

      • 单选框
      class RegForm(forms.Form):
          gender = forms.ChoiceField(choices=((1,"男"),(2,"女")))
      
      • html源码效果:

    • initial

      • 提供默认值
      class RegForm(forms.Form):
          name = forms.CharField(
              label="用户名",
              min_length=6,
              initial="刘大牛",
          )
      
      • 网页效果

    • error_messages

      • 错误提示信息设置

        class RegForm(forms.Form):
            name = forms.CharField(
                label="用户名",
                min_length=6,
                required= True,
                error_messages={
                    "required":"用户名是必须填写的",
                    "min_length":"用户名长度不能小于6位"
        
                },
            )
        
      • 网页效果

    • required

      • 默认值为True,表示当前字段的值必须填写,

        class RegForm(forms.Form):
            name = forms.CharField(
                label="用户名",
                required = True,
            )
        
      • 网页效果:未填写,点击提交

    • radioselect

      • 把select 框改变样式变成按钮选项框

            class RegForm(forms.Form):
                gender = forms.ChoiceField(
                    choices=((1,"男"),(2,"女")),
                    widget = forms.RadioSelect,
                )
        
      • 网页效果:

    • MultipleChoiceField

      • 多选选择框

        hobby = forms.MultipleChoiceField(
                choices=((1,"篮球"),(2,"足球"),(3,"双色球"))
            )
        
      • 网页效果:

        多选框关联数据库
        choices = models.Hobby.objects.values_list("id","name")
        

        存在问题:

        如果在数据库中增加记录,会发现页面没有显示增加的字段。
        原因分析:
        	数据库更新数据。页面不能时时更新,原因py文件从上到下执行,数据通过实例化拿取数据,但views.py文件只加载一次,不会重新定义类,还会用之前数据,新增页面不显示,想要让数据实时更新方法如下
        
        #方式1
        hobby = forms.MultipleChoiceField()
        class RegForm(forms.Form):
            hobby = forms.MultipleChoiceField()
        	def __init__(self,*args,**kwargs):
        		super(RegForm,self).__init__(*args,**kwargs)
        		#self.fields能拿到所有字段的对象,是个字典
        		self.fields["hobby"].choices = models.Hobby.objects.values_list("id","name")
        #方式2:
        models.py的Myhobby设置__str__
        hobby = forms.ModelMultipleChoiceField(
                queryset=models.Myhobby.objects.all()
            )
        
        
        
      
    • 常用字段

    CharField
    ChoiceField
    MultipleChoiceField
    
    • Django 所有内置字段汇总
    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类型
    

    5.校验

    1.内置校验

    required = True
    min_length
    max_length
    form_obj.cleaned_data
    --->清洗数据,数据校验完毕才会有这条数据。   
    

    2.自定义校验器validators

    • 遵循规律:通过校验规则 不做任何操作,不通过校验 抛出异常

    • 示例1

    from django import forms
    from django.core.validators import RegexValidator#用于正则匹配
    class RegForm(forms.Form):
      
        phone = forms.CharField(
            validators = [
                RegexValidator(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$',"手机格式不正确"),
            ]
        )
    
    • 示例2
    #views.py端
    from django import forms
    from django.core.exceptions import ValidationError
    def testuserinfo(value):
        ret = "成功"
        if "xxx" == value:
            ret = "用户名存在"
        raise ValidationError(ret)
    class RegForm(forms.Form):
        userinfo = forms.CharField(
            required = True,
            error_messages = {
                "required":"不能为空",
                "min_length":"小于8位"
            },
            min_length=8,
            validators=[testuserinfo,
    
                        ],
        )
        #required,min_length为内置校验
        #testuserinfo自定义校验器
        #自定义校验,如果不满足要求,就引发ValidationError错误
        
    #html端
    <div>
    	<label for="{{ form_obj.userinfo.id_for_label }}">{{ form_obj.userinfo.label }}</label>
    	{{ form_obj.userinfo }}
    	{{ form_obj.userinfo.errors.0 }}
    </div>
    

    3.钩子函数

    • 通过钩子方法实现Form类中定义钩子函数,来实现自定义的验证功能
    3.1局部钩子
    • 我们在form类中定义:clean_字段名()方法,就能够实现对特定字段进行校验。
      • 局部钩子,通过校验规则 必须返回当前字段值,不通过抛出异常
    from django import forms
    from django.core.exceptions import ValidationError
    class RegForm(forms.Form):
    	username = forms.CharField(
    		label = "用户名",
    		min_length = 6,
    		initial = "Bug",
            widget=forms.widgets.TextInput(attrs={"class": "form-control"})
            
    	)
        #定义局部钩子,用来验证username字段,之前的校验还在,只是提供一个添加一些校验功能钩子
        def clean_username(self):
            v = self.cleaned_data.get("username")
            if "xxxxxxxx" in v:
                raise ValidationError("不正确")
            else:
                return v
    
    3.2全局钩子
    • 我们在Fom类中定义 clean() 方法,就能够实现对字段进行全局校验,字段全部验证完,局部钩子也全部执行完之后,执行这个全局钩子校验。
      • 通过校验规则,必须返回当前所有字段的值。不通过校验,抛出异常,调用全局出现__all__(全局的错误)
    • 验证2次密码是否输入一致
    from django.core.exceptions import ValidationError
    from django import forms
    class RegForm(forms.Form):
    	pwd = forms.CharField(label="密码",widget=forms.PasswordInput)
        ret_pwd = forms.CharField(label="密码",widget=forms.PasswordInput)
        def clean(self):
            pwd = self.cleaned_data.get("pwd")#获取第一次输入密码
            ret_pwd = self.cleaned_data.get("ret_pwd")
            if pwd == ret_pwd:
                return self.cleaned_data#如果一致则返回
            else:
                self.add_error("ret_pwd","两次输入不一致")
                raise ValidationError("两次输入不一致")
    
    

    6.is_valid的流程:

    1.执行full_clean()的方法:
    
    定义错误字典
    
    定义存放清洗数据的字典
    
    2.执行_clean_fields方法:
    
    	循环所有的字段
    
    	获取当前的值
    
     	对进行校验 ( 内置校验规则   自定义校验器)
    
    1. 通过校验
    
       self.cleaned_data[name] = value 
    
       如果有局部钩子,执行进行校验:
    
       通过校验——》 self.cleaned_data[name] = value 
    
       不通过校验——》     self._errors  添加当前字段的错误 并且 self.cleaned_data中当前字段的值删除掉
    
       2. 没有通过校验
    
       self._errors  添加当前字段的错误
    
    3.执行全局钩子clean方法
    

    7.is_valid()流程详细(源码解析):

    当我们定义一个类
    from django import forms
    class RegForm(forms.Form):#继承Form
    	pass
    def form_login(request):
        form_obj = RegForm()#未传入参数,此时没有data,返回False
        if request.method == "POST":
            form_obj = RegForm(data=request.POST)#data传入参数,此时data不为None is_bound返回True
    
            # print(form_obj)
            if form_obj.is_valid():#返回值True或False
                print(form_obj.clean())
                return HttpResponse("注册成功")
        return render(request,"form_login.html",{"form_obj":form_obj})
    

  • 相关阅读:
    hdu 2196(树上点分治)
    hdu 4807(网络流 + 贪心)
    hdu4101
    hdu4216
    hdu 4219, 树形概率DP
    hdu 4127 A*搜索
    hdu 4126
    hdu 5296,15年多校1-7
    poj3436 ACM Computer Factory
    Fence
  • 原文地址:https://www.cnblogs.com/xujunkai/p/11848414.html
Copyright © 2020-2023  润新知