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

    Form组件   (什么是form组件?为什么要用rorm组件?怎么用form组件?)

      第一大功能:对用户请求的验证--->只要用户提交数据就可以用它来验证。

      第二大功能:生成HTML代码

    前端发送请求,后台得到前端发送的内容,如果要存到数据库中需要对传过来的数据做验证,返回页面的时候,如果有错误需要在页面上展示出来。

    要求:
        1.检查是否为空
        2.检查格式是否正确
    比如: 对用户名的要求不能为空,长度在6
    -8之间 对密码的要求不能为空,必须字母数字,长度必须大于8位 对邮箱的要求不能为空,必须是邮箱格式 对年龄的要求不能为空,必须是整数类型

    我们要做的是

      模板层怎么提交数据

      视图层怎么获取数据,怎么校验数据

      校验完数据后

        1、我们需要将正确的如果写入数据库

        2、我们将验证时出现的错误信息在提交的页面上显示出来

    Form组件校验字段功能

    第一步:创建一个类。创建类必须引入和继承下面写的

    from django import forms
    class MyForm(forms.Form):

    第二步:类中创建字段(包含正则表达式)。必须引入下面写的

    from django import forms
    from django.forms import fields
    class MyForm(forms.Form):
        user = fields.CharField(max_length=20,min_length=1,required=True)

    以上的意思是创建了一个类,写了一些字段,字段相应的设置了一些约束条件。最长18,最短1,不能为空。

    用它定制的规则来验证用户发送的请求。把有用的信息提取出来才能进行操作。对应关系是:前端的input标签的name等于个什么就对应这里写的MyForm里面的字段名等于什么。比如前端在name是email的input标签里输入的值,就会与MyForm类的email字段里的规则进行比对。

    models模型层

    urls路由层

    views视图层

      获取前端传过来的数据

      ORM操作

        写入数据库可以是一个字段一个字段对应的写,还可以传一个字典

    templates模板层

      form表单和ajax都能向后端提交数据。

      区别:

        form提交是直接刷新页面,ajax是页面局部刷新。    

    <!--
    form表单提交数据,
        id是可以通过id值来找到这个form表单,然后进行相关操作
        action填写请求的url,
        method填请求的方式,
    input标签,
        id是可以通过id值来找到这个input标签,然后进行相关操作
        type是input输入框输
        name填写的值就是后端获取input输入内容的键,用过它可以获取input提交的内容
    -->
    <form id="fm" action="/add_user/" method="post">
        {% csrf_token %}
        <div>
            <label for="name">用户名:</label>
            <input type="text" name="name" id="name">
        </div>
        <div>
            <label for="pwd">密码:</label>
            <input type="password" name="pwd" id="pwd">
        </div>
        <div>
            <label for="email">邮箱:</label>
            <input type="text" name="email" id="email">
        </div>
        <input type="submit" value="form提交">
        <input id="ajax_Btn" type="button" value="ajax提交">
    </form>
    
    <!--
    ajax
        需要引入jquery文件
        需要给ajax提交按钮绑定事件让它去提交数据
        如何获取标签里的数据这里要用到JavaScript的知识
    -->
    <script src="/static/jquery.js"></script>
    <script>
        $('#ajax_Btn').on('click',function () {
            $.ajax({
                url:'/add_user/',
                type:'post',
                //serialize()方法是获取
                data:$('#fm').serialize(),
                success:function (data) {
                    //对后台返回的数据的具体操作
                    console.log(data);
                },
            })
        })
    </script>
    form与ajax的最简单写法

    检验字段功能的代码:

    from django.shortcuts import render,redirect
    
    from django import forms
    from django.forms import fields
    class MyForm(forms.Form):
        name = fields.CharField(max_length=20,min_length=1,required=True)
        pwd = fields.CharField(max_length=16,min_length=6,required=True)
        age = fields.IntegerField(required=True)
        email = fields.EmailField(required=True)
    View Code

    渲染错误信息功能

        <div>
            <label for="name">用户名:</label>
            <input type="text" name="name" id="name"><span>{{ errors_Msg.name }}</span>
        </div>
        <div>
            <label for="pwd">密码:</label>
            <input type="password" name="pwd" id="pwd">{{ errors_Msg.pwd }}
        </div>
        <div>
            <label for="age">年龄:</label>
            <input type="text" name="age" id="age">{{ errors_Msg.age }}
        </div>
        <div>
            <label for="email">邮箱:</label>
            <input type="email" name="email" id="email">{{ errors_Msg.email }}
        </div>
        <input type="submit" value="form提交">
    {#    <input id="ajax_Btn" type="button" value="ajax提交">#}
    </form>
    html

    出现这种情况是因为一个输入框可能同时出现两个错误。

    解决方法就是我们只取错误提示的第一个。

        <div>
            <label for="name">用户名:</label>
            <input type="text" name="name" id="name"><span>{{ errors_Msg.name.0 }}</span>
        </div>
        <div>
            <label for="pwd">密码:</label>
            <input type="password" name="pwd" id="pwd">{{ errors_Msg.pwd.0 }}
        </div>
        <div>
            <label for="age">年龄:</label>
            <input type="text" name="age" id="age">{{ errors_Msg.age.0 }}
        </div>
        <div>
            <label for="email">邮箱:</label>
            <input type="email" name="email" id="email">{{ errors_Msg.email.0 }}
        </div>
        <input type="submit" value="form提交">
    {#    <input id="ajax_Btn" type="button" value="ajax提交">#}
    </form>
    解决

    如果改成中文

    from django.shortcuts import render,redirect
    
    from django import forms
    from django.forms import fields
    
    class MyForm(forms.Form):
        name = fields.CharField(
            max_length=20,
            min_length=1,
            required=True,
            error_messages={
                'required':'不能为空',
                'min_length':'太短了',
                'max_length':'太长了',
            }
        )
        pwd = fields.CharField(
            max_length=16,
            min_length=6,
            required=True,
            error_messages={
                'required': '不能为空',
                'min_length': '太短了',
                'max_length': '太长了',
            }
        )
        age = fields.IntegerField(
            required=True,
            error_messages={
                'required':'不能为空',
                # 所有遇到格式错误的都叫invalid
                'invalid':'格式错误'
            }
        )
        email = fields.EmailField(
            required=True,
            error_messages={
                'required':'不能为空',
                'invalid':'格式错误'
            }
        )
    自定义校验的类

    渲染标签(HTML)功能

    协同开发,前端写HTML,后端写form。可能写的字段和前端的name属性对应不起来。怎么解决?

    那就前端不要写了。在什么条件下生成HTML代码?

    在GET请求时,创建一个MyForm的对象,这个对象可以点出来类里面的属性。所以把这个对象也传到前端。在前端可以这么写

    def add_user(request):
        if request.method == 'GET':
            from_obj = MyForm()
            return render(request,'add_user.html',{'form_obj':from_obj})

    在前端可以这么写

    <form id="fm" action="/add_user/" method="post">
        {% csrf_token %}
        <div>
            {{ form_obj.name }}{{ errors_Msg.name.0 }}
        </div>
        <div>
            {{ form_obj.pwd }}{{ errors_Msg.pwd.0 }}
        </div>
        <div>
            {{ form_obj.age }}{{ errors_Msg.age.0 }}
        </div>
        <div>
            {{ form_obj.email }}{{ errors_Msg.email.0 }}
        </div>
        <input type="submit" value="form提交">
    </form>

    案例:

    客户通过url来访问网站展示用户信息

    通过添加按钮来添加用户,用form组件生成HTMLinput标签,get请求展示添加页面,并且进行字段校验,post请求如果前端填写的不正确要返回填写的内容以及错误信息。如果通过校验则写入数据库并且重新展示客户信息页面。

    通过编辑操作来修改当前客户的信息,还是要求用form组件生成HTML标签,get请求时要根据用户的id获取当前用户的信息,然后到编辑页面并把用户信息在页面展示出来。如果是post请求还需要进行字段校验,校验成功更新,校验失败返回错误的提示。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css">
        <title>Title</title>
    </head>
    <body>
    <a href="/add_user/">增加用户</a>
    <div class="bs-example" data-example-id="bordered-table">
        <table class="table table-bordered table-hover">
            <thead>
            <tr>
                <th>id</th>
                <th>用户名</th>
                <th>邮箱</th>
                <th>操作</th>
            </tr>
            </thead>
            <tbody>
            {% for user in user_list %}
                <tr>
                    <td>{{ user.id }}</td>
                    <td>{{ user.username }}</td>
                    <td>{{ user.email }}</td>
    {#                <td><a href="/edit_user/?nid={{ user.id }}">编辑</a></td>#}
                    <td><a href="/edit_user-{{ user.id }}/">编辑</a></td>
                </tr>
            {% endfor %}
            </tbody>
        </table>
    </div>
    </body>
    </html>
    查看用户信息的HTML模板
    <form id="fm" action="/add_user/" method="post" novalidate>
        {% csrf_token %}
        <div>
             <label for=""> 用户名</label>
            {{ form_obj.username }}{{ form_obj.errors.username.0 }}
        </div>
        <div>
             <label for=""> 邮箱</label>
            {{ form_obj.email }}{{ form_obj.errors.email.0 }}
        </div>
        <input type="submit" value="form提交">
    </form>
    添加用户的HTML
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Title</title>
    </head>
    <body>
    <form action="/edit_user-{{ nid }}/" method="post" novalidate>
        {% csrf_token %}
        <div>
             <label for=""> 用户名</label>
            {{ form_obj.username }}{{ form_obj.errors.username.0 }}
        </div>
        <div>
             <label for=""> 邮箱</label>
            {{ form_obj.email }}{{ form_obj.errors.email.0 }}
        </div>
    
        <input type="submit" value="提交">
    </form>
    </body>
    </html>
    编辑用户的HTML
    from django import forms
    from django.forms import fields
    
    
    class MyForm(forms.Form):
        username = fields.CharField(
            max_length=20,
            min_length=2,
            required=True,
            error_messages={
                'max_length': '太长了',
                'min_length': '太短了',
                'required': '不能为空',
                'invalid': '格式不正确'
            })
        email = fields.EmailField(
            required=True,
            error_messages={
                'required': '必须填写邮箱',
                'invalid': '格式填写错误'
            }
        )
    检验字段的form类
    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^users/', views.users),
        url(r'^add_user/', views.add_user),
        url(r'^edit_user-(d+)/', views.edit_user),
    ]
    urls路由
    from django.shortcuts import render,redirect
    from app01 import models
    
    from app01.myforms import MyForm
    
    
    def users(request):
        if request.method == 'GET':
            user_list = models.UserInfo.objects.all()
            return render(request,'userInfo.html',{'user_list':user_list})
        elif request.method == 'POST':
            # return redirect('/get_userInfo/')
            return redirect('https://www.baidu.com')
    
    def add_user(request):
        if request.method == 'GET':
            from_obj = MyForm()
            return render(request,'add_user.html',{'form_obj':from_obj})
        elif request.method == 'POST':
            # 数据与规则进行比对
            # 会自动去取前端的请求,比较完了之后产生一个结果,如果错误有错误信息,如果正确了会将正确数据给你。
            form_obj = MyForm(request.POST)
            if form_obj.is_valid():
                models.UserInfo.objects.create(**form_obj.cleaned_data)
                return redirect('/users/')
            else:
                print('验证失败',form_obj.errors)
            return render(request,'add_user.html',{'form_obj':form_obj})
    
    
    
    def edit_user(request,nid):
        if request.method == 'GET':
            # 从数据库拿数据到前端渲染
            user_data = models.UserInfo.objects.filter(id=nid).first()
            form_obj = MyForm({'username':user_data.username,'email':user_data.email})
            return render(request,'edit_user.html',{'form_obj':form_obj,'nid':nid})
        elif request.method == 'POST':
            form_obj = MyForm(request.POST)
            if form_obj.is_valid():
                models.UserInfo.objects.filter(id=nid).update(**form_obj.cleaned_data)
                return redirect('/users/')
            else:
                return render(request, 'edit_user.html',{'form_obj':form_obj,'nid':nid})
    视图函数的逻辑代码

    相关的mysql数据库配置、数据库表设计我们这里就不展示了。但是用form组件来生成HTML标签一定要注意对应关系,from的字段必须和input标签的对应。

    form字段

    创建Form类时,主要涉及到 【字段】 和 【插件】,字段用于对用户请求数据的验证,插件用于自动生成HTML;

    我们自己写的类的字段它继承了Field:也就是django内置的字段

      1 Field
      2     required=True,               是否允许为空
      3     widget=None,                 HTML插件
      4     label=None,                  用于生成Label标签或显示内容
      5     initial=None,                初始值
      6     help_text='',                帮助信息(在标签旁边显示)
      7     error_messages=None,         错误信息 {'required': '不能为空', 'invalid': '格式错误'}
      8     show_hidden_initial=False,   是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直)
      9     validators=[],               自定义验证规则
     10     localize=False,              是否支持本地化
     11     disabled=False,              是否可以编辑
     12     label_suffix=None            Label内容后缀

    如果字段是CharField格式里面常用的参数有:

    • required:True   不允许为空
    • max_length=18  最大长度为18
    • min_length=2    最小长度为2
    • strip:True         移除用户输入的空白

    如果字段是IntegerField格式里面常用的参数

    • min_value=0     最小值
    • max_value=110  最大值
    DecimalField(IntegerField)
        max_value=None,              最大值
        min_value=None,              最小值
        max_digits=None,             总长度
        decimal_places=None,         小数位长度
    DateField(BaseTemporalField)    格式:2015-09-01
    DateTimeField(BaseTemporalField)格式:2015-09-01 11:12
    FileField(Field)
        allow_empty_file=False     是否允许空文件
    ImageField(FileField)      
        ...
        注:需要PIL模块,pip3 install Pillow
         以上两个字典使用时,需要注意两点:
            - form表单中 enctype="multipart/form-data"
             - view函数中 obj = MyForm(request.POST, request.FILES)
     ChoiceField(Field)
        ...
        choices=(),                选项,如:choices = ((0,'上海'),(1,'北京'),)
         required=True,             是否必填
         widget=None,               插件,默认select插件
        label=None,                Label内容
        initial=None,              初始值
         help_text='',              帮助提示

    多选框

    MultipleChoiceField(ChoiceField)

    字符串转换成int类型

    TypedChoiceField(ChoiceField)
         coerce = lambda val: val   对选中的值进行一次转换
         empty_value= ''            空值的默认值
    TypedMultipleChoiceField(MultipleChoiceField)
        coerce = lambda val: val   对选中的每一个值进行一次转换
       empty_value= ''            空值的默认值
    GenericIPAddressField
         protocol='both',           both,ipv4,ipv6支持的IP格式
         unpack_ipv4=False          解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用
    from django import forms
    from django.forms import fields
    from django.forms import widgets
    
    
    class UserForm(forms.Form):
        user = fields.CharField(
            max_length=20,
            min_length=2,
            required=True,
            label='用户名:',
            initial='请输入用户名',
            error_messages={
                'max_length': '太长了',
                'min_length': '太短了',
                'required': '不能为空',
            }
        )
        age = fields.IntegerField(
            required=True,
            min_value=0,
            max_value=110,
            label='年龄:',
            error_messages={
                'max_value': '年龄太大了',
                'min_value': '年龄太小了',
                'required': '不能为空',
            }
        )
        email = fields.EmailField(
            label='邮箱:',
            initial='请填写你的邮箱',
        )
        file = fields.FileField(
            label='文件:',
    
        )
    
        # ChoiceField生成下拉框
        city = fields.ChoiceField(
            label='城市:',
            choices=[(1, 'beijing'), (2, 'nanjing'), (3, 'shanghai')],
            initial=3,  # 默认选择3上海
        )
    
        hobby = fields.MultipleChoiceField(
            label='爱好',
            choices=[(1, 'read'), (2, 'music'), (3, 'traveling'), (4, 'swimming')],
            #设置默认值,列表
            initial=[1,2]
        )
    自定义规则

      

    form插件

    插件的作用是自定义生成HTML标签,在每个插件里面可以给当前生成的这个标签自定义属性,属性叫attrs。

    如果是对于特殊的下拉框对它的select或者是有这种数据源的东西的时候,我们用choices。

    django内置的插件

     1 TextInput(Input)
     2 NumberInput(TextInput)
     3 EmailInput(TextInput)
     4 URLInput(TextInput)
     5 PasswordInput(TextInput)
     6 HiddenInput(TextInput)
     7 Textarea(Widget)
     8 DateInput(DateTimeBaseInput)
     9 DateTimeInput(DateTimeBaseInput)
    10 TimeInput(DateTimeBaseInput)
    11 CheckboxInput
    12 Select
    13 NullBooleanSelect
    14 SelectMultiple
    15 RadioSelect
    16 CheckboxSelectMultiple
    17 FileInput
    18 ClearableFileInput
    19 MultipleHiddenInput
    20 SplitDateTimeWidget
    21 SplitHiddenDateTimeWidget
    22 SelectDateWidget

    常用插件: 

    # 单radio,值为字符串
    # user = fields.CharField(
    #     initial=2,
    #     widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),))
    # )
     
    # 单radio,值为字符串
    # user = fields.ChoiceField(
    #     choices=((1, '上海'), (2, '北京'),),
    #     initial=2,
    #     widget=widgets.RadioSelect
    # )
     
    # 单select,值为字符串
    # user = fields.CharField(
    #     initial=2,
    #     widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
    # )
     
    # 单select,值为字符串
    # user = fields.ChoiceField(
    #     choices=((1, '上海'), (2, '北京'),),
    #     initial=2,
    #     widget=widgets.Select
    # )
     
    # 多选select,值为列表
    # user = fields.MultipleChoiceField(
    #     choices=((1,'上海'),(2,'北京'),),
    #     initial=[1,],
    #     widget=widgets.SelectMultiple
    # )
     
     
    # 单checkbox
    # user = fields.CharField(
    #     widget=widgets.CheckboxInput()
    # )
     
     
    # 多选checkbox,值为列表
    # user = fields.MultipleChoiceField(
    #     initial=[2, ],
    #     choices=((1, '上海'), (2, '北京'),),
    #     widget=widgets.CheckboxSelectMultiple
    # )

    数据源无法时时更新,有两种方法 

     方式一:重构构造方法(推荐)

    方法一:重构构造方法(推荐)
        class ClassesForm(Form):
        name = fields.CharField(
            required=True,  # 必填字段
            error_messages={"required": "姓名不能为空!!"},  # 显示中文错误提示
            widget=widgets.TextInput(attrs={"placeholder": "姓名", "class": "form-control"}),  # 自动生成input框
        )
        # 如果直接定义成classteacher_id,,_id 的形式,这样你添加数据的时候不会时时更新,所以在下面定义一个重写的方法
        # classteacher_id = fields.ChoiceField(choices= models.UserInfo.objects.filter(ut_id = settings.ROLE_CLASSTEACHER).values_list('id', "username"))
    
            classteacher_id = fields.ChoiceField(choices=[])
            def __init__(self,*args,**kwargs):   #重写init方法,时时更新
                super().__init__(*args,**kwargs)   #继承父类
     
                self.fields["classteacher_id"].choices = models.UserInfo.objects.filter(ut_id = settings.ROLE_CLASSTEACHER).values_list('id', "username")
        注意:
            要是这样:fields.ChoiceField(choices=[])
            注意choices里面传[(1,"讲师"),(2,"班主任"),(3,"管理员")]所以数据库里取的时候得用values_list

     Form基本使用

    类
        字段
        is_valid()
        cleaned_data
        errors
        字段参数:
            max_length
            min_length
            validators = [RegexValidators("xxx")]
            
        钩子函数
            clean_字段名
            注意:
                必须有返回值
                只能拿自己当前字段值
                raise ValidationError("xxx")
        下拉框数据源时时更新
            1、重写init方法
                先执行父类构造方法
                self.fields["xx"].choices = xxxxx
            2、ModelChoiceField

    end

  • 相关阅读:
    SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder"
    Tomcat跨域
    Invalid bean definition with name 'dataSource' defined in class path resource [applicationContext.xml]
    网速测试
    程序员实用工具网站
    安装wls报(主清单位置 "/u01/app/oracle/inventory" 无效 (无法读取/写入/执行))
    pom.xml
    CUDA -- 内存分配
    最长上升子序列(LIS: Longest Increasing Subsequence)
    实例化渲染
  • 原文地址:https://www.cnblogs.com/zhangrenguo/p/10293779.html
Copyright © 2011-2022 走看看