• Django之Form组件(***)


    Django之Form组件

      Form组件,用来做一些数据的提前验证,比如登录注册中,我们定义的是邮箱登录,但是用户却手机号登录,那么用Form组件去实现这个验证过程的话,数据的判断逻辑就不会去数据库匹配啦,这样反而会减轻数据库的压力。

      所以,Form组件的功能是对用户的请求数据库做验证的。并且对获取的数据也可以做验证功能。  

      以往的登录注册中的问题:

        在以往的登录注册页面中,如果有输入错误,页面是重新刷新的,所以之前输入对的数据也会随之消失。

        重复进行用户数据的校验:正则,长度,是否为空等等。

        Form组件的解决方法:

        先导入模块:  

    from django.forms import Form
    from django.forms import fields 

      后端:

    from django.forms import Form
    from django.forms import fields
    
    class LoginForm(Form):
    “““
    字段的名称必须与前端的字典名称一致。
    ””” username
    = fields.CharField( max_length=18, min_length=6, required=True, error_messages={ "required":"用户名不能为空", "min_length":"长度不能小于6位", "max_length":"长度不能大于18位", } ) password = fields.CharField( min_length=16, required=True, error_messages={ "required": "密码不能为空", "min_length": "长度不能小于16位", } ) def login(request): if request.method == "GET": return render(request,"login.html") else: obj = LoginForm(request.POST) ret = obj.is_valid() #内部自动校验,ret是False和True的结果 if ret: #用户输入格式正确 print(obj.cleaned_data) #cleaned_data 是一个字典类型,是校验成功后拿到的值。 return redirect('http://www.baidu.com') else: #用户输入格式错误 # print(obj.errors) #所有的错误信息,这个错误信息是一个对象,是 __str__ 方法 # print(obj.errors["username"]) # print(obj.errors["username"][0]) #在LoginForm类中定义了多个条件,那么就可能有多个错误信息,所有可以用索引取第一个 # print(obj.errors["password"]) # print(obj.errors["password"][0]) return render(request,"login.html",{"obj":obj})

      前端:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h1>登录</h1>
        <form method="post" action="login.html">
            {% csrf_token %}
            <p>username:<input type="text" name="username">{{ obj.errors.username.0 }}</p>
            <p>password:<input type="password" name="password">{{ obj.errors.password.0 }}</p>
            <input type="submit" value="submit">
        </form>
    </body>
    </html>

       到目前为止,Form组件的功能是对用户提交的数据进行校验和保留上次输入的内容。

       对于前端用户提交的方式,有两种,一个是Form提交,一种是Ajax提交。 

       其中Form提交是刷新,并失去上次的输入内容。

       而Ajax是不刷新,保留上次输入的内容。

       Form的验证流程:

        当执行is_valid的时候,Form的验证原理是:

          1. 获取当期类中所有的字段,也就是LoginForm类中,我们定义的字段。  

                 也就是当每次对LoginForm实例化的时候,会将LoginForm类中的字段放到self.fields中。这个self.fields 类似一个字典。

           self.fields = {

            "username":fields.CharField(required=Ture),  #这个对象包含了这个正则表达式。

            "password":fields.CharField(required=Ture),  #这个对象包含了这个正则表达式。

           }

          2. 会循环self.fields,被循环的个数是由LoginForm来定的,因为self.fields循环的就是LoginForm的字段的个数。

            for k,v in self.fields.items():

                k:k是每次循环的username或password,它是字符串类型。

              v:v是对应的正则表达式。

              input_value = request.POST.get(k):这个表达式的意思是POST里有很多数据。

                               这里的k是字段的名字,如何写username,那么就会去找username的数据。

              v的正则表达式的值和input_value的值进行校验。

            所以在for循环之前,先定义一个flag=Ture.

            当v的正则和input_value校验不匹配时,返回False的值。

    flag = Ture
    for k,v in self.fields.items():
        input_value = request.POST.get(k)
        flag = False
    return flag

      以上的Form流程就是is_valid的原理。

        is_valid 是True的话,获取cleaned_data的数据。

       Form组件和Ajax的提交验证:

        用Ajax的形式将前端的数据发送给后台:

        前端代码:  

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h1>用户登录</h1>
        <form id="f1" method="post" action="login.html">
            {% csrf_token %}
            <p>username:<input type="text" name="username">{{ obj.errors.username.0 }}</p>
            <p>password:<input type="password" name="password">{{ obj.errors.password.0 }}</p>
            <input type="submit" value="submit">
            <a onclick="submitForm();">提交</a>
        </form>
        <script src="/static/jquery-1.12.4.js"></script>
        <script>
            function submitForm() {
                $.ajax({
                    url:"/ajax_login/",
                    type:"POST",
                    data:$("#f1").serialize(),   //serialize()他会将所有的input框的数据打包交给data。这里打包的有csrf和username,password。效果是username=xxx&password=xxx&csrf=xxx,这是个字符串。
                    success:function (arg) {
                        console.log(arg)
                    }
                })
            }
        </script>
    </body>
    </html>

        后端代码:

    def ajax_login(request):
        obj = LoginForm(request.POST)
        if obj.is_valid():
            print(obj.cleaned_data)
        else:
            print(obj.errors)
        return HttpResponse("...")

        这样就算是提交错误了,页面是不会刷新,并且会保留之前输入的数据。

        但这里我们实现代码会发现一个问题,那就是在错误提交数据后,也是不刷新啦,前端输入的值后端也拿到了,但是但是,有个问题点,就是前端的页面并没有错误提示呀。

        所以,这个ajax的提交并不是那么的那么的完美,所以,我们接下来,就来完善一下这个ajax提交的错误提示。

      Form组件和Ajax提交验证的显示错误信息:

        这里用到了json.dumps的序列化操作,序列化的是obj.errors的对象。

        前端代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h1>用户登录</h1>
        <form id="f1" method="post" action="login.html">
            {% csrf_token %}
            <p>username:<input type="text" name="username">{{ obj.errors.username.0 }}</p>
            <p>password:<input type="password" name="password">{{ obj.errors.password.0 }}</p>
            <input type="submit" value="submit">
            <a onclick="submitForm();">提交</a>
        </form>
        <script src="/static/jquery-1.12.4.js"></script>
        <script>
            function submitForm() {
                $('.c1').remove();
                $.ajax({
                    url:"/ajax_login/",
                    type:"POST",
                    data:$('#f1').serialize(),   //serialize()他会将所有的input框的数据打包交给data。这里打包的有csrf和username,password。效果是username=xxx&password=xxx&csrf=xxx,这是个字符串。
                    dataType:"JSON",
                    success:function (arg) {
                        console.log(arg);
                        if(arg.status){
    
                        }else {
                             $.each(arg.msg,function(index,value){
                                console.log(index,value);   //index是对应的k的值,也就是username,value是username输入的值。
                                var tag = document.createElement("span");
                                tag.innerHTML = value[0];
                                tag.className = 'c1';
                                $('#f1').find('input[name="'+ index +'"]').after(tag);
                            })
                        }
                    }
                })
            }
        </script>
    </body>
    </html>

        后端代码:

    def ajax_login(request):
        import json
        ret = {'status': True,'msg': None}
        obj = LoginForm(request.POST)
        if obj.is_valid():
            print(obj.cleaned_data)
        else:
            # print(obj.errors) # obj.errors对象
            ret['status'] = False
            ret['msg'] = obj.errors
        v = json.dumps(ret)
        return HttpResponse(v)

       这样就可以实现ajax提交有错误提示啦。

      Form组件的常见字段和参数:

        在XXXForm类中的字段:

        数字类型:

    #数字类型
    number = fields.IntegerField(
    min_value=10, #这里的min和max不是单纯的数字长度,而是数字范围。
    max_value=1000,
    #有错误信息 error_messages={ "required":"number不能为空", "invalid":"number格式错误,必须是数字", #invalid 格式错误
    "min_value":"数值必须大于10",
    "max_value":"数值必须小于1000", } )   

        邮件类型:

    #邮件类型
    Email = fields.EmailField(
        #有错误信息
        error_messages={
            "required":"Email不能为空",
            "invalid":"Email格式错误,必须是邮件格式",  #invalid 格式错误
        }
    ) 

        还有对URL的fields.URLField。

        还有fields.SlugField 和fields.GenericIPAddressField、fields.DateField、fields.DateTimeField。

        但这些内置的也会有不完善的地方,无法达到我们的需求。所以,还有fields.RegesField。

        可以用这个fields.RegesField去写正则表达式。  

    test = fields.RegesField('185d+')

        fields.RegesField是继承CharField的。

        而CharField也是继承的Field,所以,我们来看一下Field的里的参数:

      Form组件的Field类的参数:

        widget 是用来指定生成什么样的HTML标签。比如select,text,input。

        但用widget要先导入:from django.forms import widgets

     

         label:写什么就在前端页面显示什么,在前端的写法是:   

    {{ obj.字段名.label }}
      好比:
        {{ obj.t1.label }}

        initial:初始值。

        在input框中显示默认值用的。

        help_text:提供帮助信息:

    在Form的字段中定义help_text:
        help_text='.......'
    在前端代码和label一样:
    {{ obj.t1.help_text }}
    
    这样就可以在前端显示:.......啦

        validators:自定义验证规则

    validators=[ ]

        localize=False:是否支持本地化,这是用来转化时间的。

        disabled=False:是否可以编辑。

        label_suffix=None:label内容后缀。

        上述这里参数,处理validators以外。其余的一起用,是可以自动生成HTML标签的。

        这里就实现一个用后端参数实现一个前端标签的代码:

        后端:

    class TestForm(Form):
        t1 = fields.CharField(
            required=True,
            label="usename",
            label_suffix=":",
            help_text="输入username",
            disabled=False,
            initial="username",
            max_length=8,
            min_length=2,
            error_messages={
                "required":"不能为空",
                "max_length":"long",
                "min_length":"",
            }
    
        )
    
    def login(request):
        if request.method =="POST":
            obj = TestForm()
            return render(request,"login.html",{"obj":obj})
        else:
            obj = TestForm(request.POST)
            if obj.is_valid():
                print(obj.cleaned_data)
            else:
                print(obj.errors)
            return render(request,"login.html",{"obj":obj})

        前端:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h1>用户登录</h1>
        <form id="f1" method="post" action="login.html">
            {% csrf_token %}
            <p>
                {{ obj.t1.label }}{{ obj.t1.label_suffix }}
                {{ obj.t1 }}{{ obj.t1.help_text }}
            </p>
            <input type="submit" value="submit">
        </form>
    </body>
    </html>

        以上就是用后端代码实现前端的标签的。

      Form小总结:

        form有验证的功能:  

          1.类:

            字段 = 正则

          2.is_valid()

        form有生成HTML标签的功能:  

            1.类:

            字段 = 正则( 正则这里规定一些生成HTML标签的特性)

          2.is_valid()

      Form组件保留上次输入的内容:

        前端:  

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
    
        <form action="/register/" method="POST" novalidate>
            {% csrf_token %}
            <p>user:
                {{ obj.user }} {{ obj.errors.user.0 }}
            </p>
            <p>email:
                {{ obj.email }} {{ obj.errors.email.0 }}
            </p>
            <p>password:
                {{ obj.password }} {{ obj.errors.password.0 }}
            </p>
            <p>phone:
                {{ obj.phone }} {{ obj.errors.phone.0 }}
            </p>
            <input type="submit" value="提交"  />
        </form>
    </body>
    </html>

        后端:

    class RegiterForm(Form):
        user = fields.CharField(min_length=8)
        email = fields.EmailField()
        password = fields.CharField()
        phone = fields.RegexField('139d+')
    
    def register(request):
        if request.method == 'GET':
            obj = RegiterForm()
            return render(request,'register.html',{'obj':obj})  #这个obj里是没有值的,因为是第一次的请求
        else:
            obj = RegiterForm(request.POST)
            if obj.is_valid():
                print(obj.cleaned_data)
            else:
                print(obj.errors)
            return render(request,'register.html',{'obj':obj})   #这里的obj有值,值是input输入的值。

       这样输入的值就可以保留。

       Form组件小示例班级学生老师管理:

         示例中,应用到的Form特性,以后在任何的提交数据和编辑数据中,都应该应用Form组件去完成,因为我们是不信任提交的数据的。

           所有,需要用Form去做验证。

          后端views代码:    

    from django.shortcuts import render,redirect
    from app01 import models
    from django.forms import Form
    from django.forms import fields
    from django.forms import widgets
    
    
    class ClassForm(Form):
        title = fields.RegexField('全栈d+')
    
    def class_list(request):
        cls_list = models.Classes.objects.all()
        return render(request,'class_list.html',{'cls_list':cls_list})
    
    def add_class(request):
        if request.method == "GET":
            obj = ClassForm()
            return render(request,'add_class.html',{'obj': obj})
        else:
            obj = ClassForm(request.POST)
            if obj.is_valid():
                # obj.cleaned_data # 字典
                # 数据库创建一条数据
                # print(obj.cleaned_data)
                # models.Classes.objects.create(title=obj.cleaned_data['tt'])
    
                models.Classes.objects.create(**obj.cleaned_data)
                return redirect('/class_list/')
            return render(request,'add_class.html',{'obj': obj})
    
    def edit_class(request,nid):
        if request.method == "GET":
            row = models.Classes.objects.filter(id=nid).first()
            # 让页面显示初始值
            # obj = ClassForm(data={'title': 'asdfasdfasdfas'})
            obj = ClassForm(initial={'title': row.title})
            return render(request,'edit_class.html',{'nid': nid,'obj':obj})
        else:
            obj = ClassForm(request.POST)
            if obj.is_valid():
                models.Classes.objects.filter(id=nid).update(**obj.cleaned_data)
                return redirect('/class_list/')
            return render(request,'edit_class.html',{'nid': nid,'obj':obj})
    
    class StudentForm(Form):
        name = fields.CharField(
            min_length=2,
            max_length=6,
            widget=widgets.TextInput(attrs={'class': 'form-control'})
        )
        email = fields.EmailField(widget=widgets.TextInput(attrs={'class': 'form-control'}))
        age = fields.IntegerField(min_value=18,max_value=25,widget=widgets.TextInput(attrs={'class': 'form-control'}))
        cls_id = fields.IntegerField(
            # widget=widgets.Select(choices=[(1,'上海'),(2,'北京')])
            widget=widgets.Select(choices=models.Classes.objects.values_list('id','title'),attrs={'class': 'form-control'})
        )
    
    def student_list(request):
        stu_list = models.Student.objects.all()
        return render(request,'student_list.html',{'stu_list':stu_list})
    
    def add_student(request):
        if request.method == "GET":
            obj = StudentForm()
            return render(request,'add_student.html',{'obj':obj})
        else:
            obj = StudentForm(request.POST)
            if obj.is_valid():
                models.Student.objects.create(**obj.cleaned_data)
                return redirect('/student_list/')
            return render(request,'add_student.html',{'obj':obj})
    
    def edit_student(request,nid):
        if request.method == "GET":
            row = models.Student.objects.filter(id=nid).values('name','email','age','cls_id').first()
            obj = StudentForm(initial=row)
            return render(request,'edit_student.html',{'nid':nid,'obj': obj})
        else:
            obj = StudentForm(request.POST)
            if obj.is_valid():
                models.Student.objects.filter(id=nid).update(**obj.cleaned_data)
                return redirect('/student_list/')
            return render(request,'edit_student.html',{'nid':nid,'obj': obj})
    View Code

          后端models代码:

    from django.db import models
    
    class Classes(models.Model):
        title = models.CharField(max_length=32)
    
    class Student(models.Model):
        name = models.CharField(max_length=32)
        email = models.CharField(max_length=32)
        age = models.IntegerField(max_length=32)
        cls = models.ForeignKey('Classes')
    
    class Teacher(models.Model):
        tname = models.CharField(max_length=32)
        c2t = models.ManyToManyField('Classes')
    View Code

         URL:

    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^class_list/', views.class_list),
        url(r'^add_class/', views.add_class),
        url(r'^edit_class/(d+)/', views.edit_class),
    
        url(r'^student_list/', views.student_list),
        url(r'^add_student/', views.add_student),
        url(r'^edit_student/(d+)/', views.edit_student),
    ]
    View Code

         前端class_list 代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <h1>班级列表</h1>
        <div>
            <a href="/add_class/">添加</a>
        </div>
        <ul>
            {% for row in cls_list %}
                <li>{{ row.title }} <a href="/edit_class/{{ row.id }}/">编辑</a>  </li>
            {% endfor %}
        </ul>
    </body>
    </html>
    View Code

        前端add_class 代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <h1>添加班级</h1>
        <form method="POST" action="/add_class/" novalidate>
            {% csrf_token %}
            {{ obj.title }} {{ obj.errors.title.0 }}
            <input type="submit" value="提交" />
        </form>
    </body>
    </html>
    View Code

        前端edit_class 代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <h1>编辑班级</h1>
        <form method="POST" action="/edit_class/{{ nid }}/">
            {% csrf_token %}
            <p>
                {{ obj.title }} {{ obj.errors.title.0 }}
            </p>
            <input type='submit' value="提交" />
        </form>
    </body>
    </html>
    View Code

        前端student_list 代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <h1>学生列表</h1>
        <a href="/add_student/">添加</a>
        <ul>
            {% for row in stu_list %}
                <li>{{ row.name }}-{{ row.email }}-{{ row.age }}-{{ row.cls_id }}-{{ row.cls.title }}   <a href="/edit_student/{{ row.id }}/">编辑</a></li>
            {% endfor %}
        </ul>
    </body>
    </html>
    View Code

        前端add_student 代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <h1>添加学生</h1>
        <form action="/add_student/" method="POST">
            {% csrf_token %}
            <p>
                {{ obj.name }}
            </p>
            <p>
                {{ obj.email }}
            </p>
            <p>
                {{ obj.age }}
            </p>
            <p>
                {{ obj.cls_id }}
            </p>
            <input type="submit" value="提交" />
        </form>
    </body>
    </html>
    View Code

        前端edit_student 代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
        <link rel="stylesheet" href="/static/bootstrap-3.3.5-dist/css/bootstrap.css"/>
    </head>
    <body>
    
    
        <div style=" 500px;margin: 0 auto;">
            <form class="form-horizontal" method="POST" action="/edit_student/{{ nid }}/">
                {% csrf_token %}
                <div class="form-group">
                    <label class="col-sm-2 control-label">姓名:</label>
    
                    <div class="col-sm-10">
                        {{ obj.name }}
                    </div>
                </div>
                <div class="form-group">
                    <label class="col-sm-2 control-label">邮箱:</label>
    
                    <div class="col-sm-10">
                        {{ obj.email }}
                    </div>
                </div>
                 <div class="form-group">
                    <label class="col-sm-2 control-label">年龄:</label>
    
                    <div class="col-sm-10">
                        {{ obj.age }}
                    </div>
                </div>
                 <div class="form-group">
                    <label class="col-sm-2 control-label">班级:</label>
    
                    <div class="col-sm-10">
                        {{ obj.cls_id }}
                    </div>
                </div>
                <div class="form-group">
                    <div class="col-sm-offset-2 col-sm-10">
                        <input type="submit" class="btn btn-default" value="提交" />
                    </div>
                </div>
            </form>
        </div>
    </body>
    </html>
    View Code

          老师多对多:

        注意:

                Select框:
                    单选
                        cls_id = fields.IntegerField(
                            # widget=widgets.Select(choices=[(1,'上海'),(2,'北京')])
                            widget=widgets.Select(choices=models.Classes.objects.values_list('id','title'),attrs={'class': 'form-control'})
                        )
                        
                        cls_id = fields.ChoiceField(
                            choices=models.Classes.objects.values_list('id','title'),
                            widget=widgets.Select(attrs={'class': 'form-control'})
                        )
                        
                        
                        obj = FooForm({'cls_id':1})
                    多选
                        xx = fields.MultipleChoiceField(
                            choices=models.Classes.objects.values_list('id','title'),
                            widget=widgets.SelectMultiple
                        )
                        
                        obj = FooForm({'cls_id':[1,2,3]})

        老师的models 代码:

    from django.db import models
    
    class Classes(models.Model):
        title = models.CharField(max_length=32)
    
        def __str__(self):
            return self.title
    
    class Student(models.Model):
        name = models.CharField(max_length=32)
        email = models.CharField(max_length=32)
        age = models.IntegerField()
        cls = models.ForeignKey('Classes')
    
    
    class Teacher(models.Model):
        tname = models.CharField(max_length=32)
        """
        10
        """
        c2t = models.ManyToManyField('Classes')
    View Code

        老师的view后端代码:

    def teacher_list(request):
        tea_list = models.Teacher.objects.all()
        return render(request,'teacher_list.html',{'tea_list':tea_list})
    
    from django.forms import models as form_model
    
    class TeacherForm(Form):
        tname = fields.CharField(min_length=2)
        # xx = form_model.ModelMultipleChoiceField(queryset=models.Classes.objects.all())
        # xx = form_model.ModelChoiceField(queryset=models.Classes.objects.all())
    
        xx = fields.MultipleChoiceField(
            # choices=models.Classes.objects.values_list('id','title'),
            widget=widgets.SelectMultiple
        )
        def __init__(self,*args,**kwargs):
            super(TeacherForm,self).__init__(*args,**kwargs)
            self.fields['xx'].choices = models.Classes.objects.values_list('id','title')
    
    # obj = TeacherForm()
    # 1. 找到所有字段
    # 2. self.fields = {
    #       tname: fields.CharField(min_length=2)
    # }
    
    def add_teacher(request):
        if request.method == "GET":
            obj = TeacherForm()
            return render(request,'add_teacher.html',{'obj':obj})
        else:
            obj = TeacherForm(request.POST)
            if obj.is_valid():
                xx = obj.cleaned_data.pop('xx')
                row = models.Teacher.objects.create(**obj.cleaned_data)
                row.c2t.add(*xx) # [1,2]
                return redirect('/teacher_list/')
            return render(request,'add_teacher.html',{'obj':obj})
    
    def edit_teacher(request,nid):
        if request.method == "GET":
            row = models.Teacher.objects.filter(id=nid).first()
            class_ids = row.c2t.values_list('id')
            # print(class_ids)
            # id_list = []
            id_list = list(zip(*class_ids))[0] if list(zip(*class_ids)) else []
            # obj = TeacherForm(initial={'tname':row.tname,'xx':[1,2,3]})
            obj = TeacherForm(initial={'tname':row.tname,'xx':id_list})
            return render(request,'edit_teacher.html',{'obj':obj})
    View Code

        老师的teacher_list 前端代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <h1>老师列表</h1>
        <div>
            <a href="/add_teacher/">添加</a>
        </div>
        <table border="1">
            <thead>
                <tr>
                    <th>ID</th>
                    <th>老师姓名</th>
                    <th>任教班级</th>
                    <th>编辑</th>
                </tr>
            </thead>
            <tbody>
                {% for row in tea_list %}
                    <tr>
                        <td>{{ row.id }}</td>
                        <td>{{ row.tname }}</td>
                        <td>
                            {% for item in row.c2t.all %}
                                <span>{{ item }}</span>
                            {% endfor %}
                        </td>
    
                        <td>
                            <a href="/edit_teacher/{{ row.id }}/">编辑</a>
                        </td>
                    </tr>
                {% endfor %}
            </tbody>
        </table>
    
    </body>
    </html>
    View Code

        老师的add_teacher 前端代码:  

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <form method="POST" action="/add_teacher/">
            {% csrf_token %}
    
            <p>
                姓名:{{ obj.tname }}
            </p>
            <p>
                班级:{{ obj.xx }}
            </p>
            <input type="submit" value="提交" />
        </form>
    </body>
    </html>
    View Code

        老师的edit_teacher 前端代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <h1>编辑老师</h1>
        <form>
            {{ obj.tname }}
            {{ obj.xx }}
        </form>
    </body>
    </html>
    View Code

       Form组件的常用组件:

        CheckBox复选框的应用:

        test后端:

    class TestForm(Form):
          t1 = fields.CharField(
              widget=widgets.Textarea(attrs={})
          )
    
          t2 = fields.CharField(   #单选的
              widget=widgets.CheckboxInput
          )
     
          t3 = fields.MultipleChoiceField(   #多选
              choices=[(1,'篮球'),(2,'足球'),(3,'溜溜球')],
              widget=widgets.CheckboxSelectMultiple
          )
    
          t4 = fields.ChoiceField(  #单选,选择互斥
              choices=[(1,'篮球'),(2,'足球'),(3,'溜溜球')],
              widget=widgets.RadioSelect
          )
    
          t5 = fields.FileField(   #上传文件
              widget=widgets.FileInput
          )
    def test(request):
        obj = TestForm(initial={'t3':[2,3]})  #默认选中
        obj.is_valid()
        return render(request,'test.html',{'obj':obj})

        test前端:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        {{ obj.t2 }}
        {{ obj.t3 }}
        {{ obj.t4 }}
        {{ obj.t5 }}
    </body>
    </html>

       Form验证执行流程和钩子:

        is_valid方法的内部流程:

           is_valid的里面有一个return的返回,返回的有self.is_bound 和 self.errors。

            这个self.is_bound是只有True和False两个值,在初始化的时候,会进行校验,这个校验的值就是True 和 False。

            在self.errors里面有一个self.full_clean方法,这个方法就是去做验证的。这个验证就是循环Form自己的字段,

            然后去提交的数据进行校验。

              在self.full_clean里面,我们可以看到有cleaned_data,这就是我们的校验数据,这是一个字典类型。

              最后是clean_fields处理data的数据。      

    self._clean_fields()  #做cleaned_data数据处理用
    self._clean_form()   #做钩子用
    self._post_clean()

        钩子:是自己定义的,当定义的钩子函数被调用是当每一个字段,自己的正则表达式,自己的函数后执行完,才会执行这个钩子函数。

           如果想用钩子函数,那么cleaned_data里是已经有值的啦。       

        样例:   

    from django.core.exceptions import ValidationError
    class TestForm(Form):
        user = fields.CharField(validators=[])
        pwd = fields.CharField()
    
        def clean_user(self):
            v = self.cleaned_data['user']
            if models.Student.objects.filter(name=v).count():
                raise ValidationError('用户名已经存在')
            return self.cleaned_data['user']
    
        def clean_pwd(self):
            return self.cleaned_data['pwd']
    
        def clean(self):   #钩子
            # user = self.cleaned_data.get('user')
            # email = self.cleaned_data.get('email')
            # if models.Student.objects.filter(user=user,email=email).count():
            #     raise ValidationError('用户名和邮箱联合已经存在')
            return self.cleaned_data
        # def _post_clean(self):
        #     """
        #     An internal hook for performing additional cleaning after form cleaning
        #     is complete. Used for model validation in model forms.
        #     """
        #     pass

       Form扩展:

          字段 = 默认的正则表达式。

          在默认的正则中,可以在加额外的正则,用validators=[]

        clean_字段 = 必须有返回值。

        clean():有返回值,用定义的返回值 cleaned_data = 返回值。

            没有返回值,用原来的值,cleaned_data = 原有的值。

        Form的验证流程:

          1. 写一个Form,用户提供大量的验证数据,先一个一个字段的去获取。

          2. 拿一个字段,做自己的正则,当自己的正则执行完,就执行自己的函数。

          3. 所有的字段执行完自己函数后,执行clean()方法。

       Form组件总结:    

        1. 使用
          class Foo:
            xx = xxxxxx() # 正则,插件

            def clean_xx():
              ...
            def clean():
              pass

        2. 页面展示
          obj = Foo()

          # 灵活
          <form>
            {{obj.xx}}
            {{obj.xx}}
            {{obj.xx}}
          </form>

          # 简单
          {{obj.as_p}}
          <ul>
            {{obj.as_ul}}
          </ul>
          <table>
            {{obj.as_table}}
          </table>

        3. 后台
          is_valid()
          clean_data
          errors

       参考blog:XXXXXXXX6144178.html

    ------- END -------

  • 相关阅读:
    java前端学习步骤
    安装Sublime Text 3插件的方法(转自Rising的博文)
    LibSVM学习详细说明
    class 2-3 小项目练习
    class 2-2 小项目练习
    class 2-1 小项目练习
    class 1-1 python开发环境配置
    Class
    class 10 文件和异常
    class
  • 原文地址:https://www.cnblogs.com/george92/p/11441796.html
Copyright © 2020-2023  润新知