之前我们已经学习了HTML中的基本标签——form表单,我们经常使用它向后台提交数据,常规的form表单是这样的:

<form action="" method="post">
    <p>用户名:<input type="text" name="user"></p>
    <p>密码:<input type="text" name="pwd"></p>
    <P><input type="submit"></P>
</form>

但是有许多时候我们这样使用非常不方便,为什么这样说了,上面的form表单中只有两个提交项,

但是实际中肯定不止两个,如果使用上面的方式,那么一旦有哪一个提交项不符合规定,整个form表单都得重写,

这是后用户肯定会抱怨,“凭什么错了一个全部得重写”,所以这样不方便,还有一个就是在对输入的东西值进行校验的时候,

每次都得先从前面取值,再在后台校验,烦不烦,能不能在后台生成得时候就设置好了?

这就是jango中form组件可以非常好的解决得问题。下面会一步一步解开解开它得面纱。

 

 

一、在Django中构建一个from表单

下面创建一个最简单的form表单:

from django.shortcuts import render
#导入forms组件
from django import forms

class LoginForm(forms.Form):
    user = forms.CharField(max_length=10)
    pwd = forms.CharField()

def login(request):
    #实例化一个对象
    form_obj = LoginForm()
    return render(request,"login.html",{"form_obj":form_obj})

在前端页面中展示form_obj:

{{ form_obj.as_p }}

as_p是一个特殊的属性,常见的有:

  • {{ form.as_table }} 以表格的形式将它们渲染在<tr> 标签中
  • {{ form.as_p }} 将它们渲染在<p> 标签中
  • {{ form.as_ul }} 将它们渲染在<li> 标签中

 

下面是效果:

Django——form组件

可以看一下前端页面:

Django——form组件

可以看到它自动给你生成了两个input标签,但是还缺一个提交按钮,form组件能不能做了,答案是不能,还得你自己写。

刚才展示了一种前端加载得方法,还有另外一种比较灵活得方法,不过需要我们添加更多的标签。

<form action="" novalidate method="post">
    {% csrf_token %}
    <div>
        <label for="">用户名</label>
        {{ form_obj.user }}
    </div>
    <div>
        <label for="">密码</label>
        {{ form_obj.pwd }}
    </div>
    <input type="submit">
</form>

得到得效果就是:

Django——form组件

貌似现在还看不出来form组件得作用,不急我们慢慢来。

注意:

(1)novalidate这个属性是关闭浏览器的自动校验。

(2)Django 原生支持一个简单易用的跨站请求伪造的防护。当提交一个启用CSRF 防护的POST 表单时,你必须使用上面例子中的csrf_token 模板标签

 

二、form组件的两大功能展示

1.保存之前的输入值

def login(request):
    #如果进行的是提交操作
    if request.method == "POST":
        #再次实例化一个对象,但是与get请求不同的是,这里form_obj是有值。
        form_obj = LoginForm(request.POST)
        return render(request, "login.html", {"form_obj": form_obj})
    #实例化一个对象
    form_obj = LoginForm()
    return render(request,"login.html",{"form_obj":form_obj})

注意:两个form_obj是不一样的,一个是带着值进行渲染的,一个是空值,这也是为什么提交不会清除掉原来的值得原因了。

 

2.校验

Form的实例具有一个is_valid()方法,它会对输入的字段进行校验,如果所有的字段都合法,那么他就会:

  • 返回True
  • 将表单的数据放到cleaned_data属性中。

在创建类的时候,我们其实可以给这个属性加上约束,就像这样:

user = forms.CharField(max_length=10,min_length=5)
#最大长度为10,最小长度为5,这样就可以校验了

From实例的对象还有一个errors方法,是所有字段所有约束的错误信息,我们可以将其打印出来:

def login(request):
    #如果进行的是提交操作
    if request.method == "POST":
        #再次实例化一个对象,但是与get请求不同的是,这里form_obj是有值。
        form_obj = LoginForm(request.POST)
        if form_obj.is_valid():
            return HttpResponse("登录成功")
        else:
            print(form_obj.errors)
            print(type(form_obj.errors))
            print(form_obj.errors["user"])
            print(type(form_obj.errors["user"]))
            return render(request, "login.html", {"form_obj": form_obj})
    #实例化一个对象
    form_obj = LoginForm()
    return render(request,"login.html",{"form_obj":form_obj})

下面是打印结果:

print(form_obj.errors)
#这是个什么东西我们不知道
<ul class="errorlist"><li>user<ul class="errorlist"><li>Ensure this value has at least 5 characters (it has 3).</li></ul></li></ul>

#打印一下类型
print(type(form_obj.errors))
#可以猜测出它是一个错误字典
<class 'django.forms.utils.ErrorDict'>

#既然是字典,那么每个属性肯定就是键了,取出一个键
print(form_obj.errors["user"])
#这是什么我们也不知道,但是其中有英文报错
#最少5个,你只有3个
<ul class="errorlist"><li>Ensure this value has at least 5 characters (it has 3).</li></ul>

#打印一下类型
print(type(form_obj.errors["user"]))
#可以看到是一个列表,列表中的是各种约束的报错信息
<class 'django.forms.utils.ErrorList'>

#在这里不管有几个报错信息,我们只取一个就够了,如果还有错误,接着改就是了,这也符合现实情况。
print(form_obj.errors["user"][0])
#成功取出了报错信息
Ensure this value has at least 5 characters (it has 3).

既然这样,在前端就可以显示了:

<div>
        <label for="">用户名</label>
        {{ form_obj.user }}<span>{{ form_obj.user.errors.0 }}</span>
 </div>

显示效果就是:

Django——form组件

但是是英文的,可不可以是中文了?当然可以:

在属性的约束中有一个error_messages,可以让我们自行进行约束:

class LoginForm(forms.Form):
    user = forms.CharField(max_length=10,min_length=5,
                           error_messages={
                               "min_length":"最小长度为5",
                               "max_length":"最大长度为10",
                               "required":"不能为空",  #不能为空
                           })

结果如下:

Django——form组件

能不能跳一跳样式了》这样不好看,这个后面再说,现在还有一个问题,密码问题,

Django——form组件

我们发现输入的密码不能隐藏。

之所以一直没有举例,是因为文本输入有Charfield,并没有Passwordfield,在这里需要借助widget这个约束进行密码输入。

先进行导入:

from django.forms import widgets

然后设计类的时候调用:

    pwd = forms.CharField(
        error_messages={
            "required":"不能为空",
        },
        widget=widgets.PasswordInput()
    )

效果如下:

Django——form组件

在widgets中有很多限制,不是只有PasswordInput这一个,还有TextInput、CheckboxInput、NumberInput等。

在widgets中还可以进行属性的设置,例如:

    pwd = forms.CharField(
        error_messages={
            "required":"不能为空",
        },
        widget=widgets.PasswordInput(attrs={"class":"active","id":"s1"})
    )

这样就可以自行设计样式了,在前端查看:

 Django——form组件

 

 

三、高级进阶:钩子的设定

很多时候,我们想要自行设计校验的手段,该如果做了,Django给我们提供了钩子这一手段:

先来看一段源码:

               if hasattr(self, 'clean_%s' % name):
                    value = getattr(self, 'clean_%s' % name)()
                    self.cleaned_data[name] = value

这段源码是能够设置钩子的来源。

#局部钩子
    def clean_user(self):
        val1 = self.cleaned_data.get("user")
        #如果这个字符串全部都是由数组组成
        if not val1.isdigit():
            return val1
        else:
            # 注意这个报错信息已经确定了
            raise ValidationError("用户名不能全部是数字组成")

还可以设置全局钩子:

    def clean(self):
        pwd=self.cleaned_data.get("pwd")
        repeat_pwd=self.cleaned_data.get("repeat_pwd")
        if pwd==repeat_pwd:
            print("yes")
            return self.cleaned_data
        else:
            print("no")
            raise ValidationError("两次密码不一致!")

为什么有全局钩子了,因为每一个钩子都是和某个具体的字段绑定,只能获取自己的字段值,不能获取其他的值,所以需要全局钩子。

from django.shortcuts import render,HttpResponse

# Create your views here.

from django import forms
from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
from django.forms import widgets
import re
from appo1 import models

class LoginForm(forms.Form):
    user = forms.CharField(min_length=6,max_length=12,
                           error_messages={
                               "required":"用户名不能为空",
                               "min_length":"最小长度为5",
                               "max_length":"最大长度为12"
                           },
                           widget=widgets.TextInput(attrs={"id":"s1"})
                           )
    
    pwd = forms.CharField(min_length=6,
        error_messages={
            "required":"密码不能为空",
            "min_length":"最小长度为6"
        }
    )

    repeat_pwd = forms.CharField(
        error_messages={
            "required": "必须输入",
        }
    )
    
    email = forms.EmailField(
        error_messages={
            "required": "",
            "invalid":"格式错误"
        }
    )
    
    phone = forms.CharField(
        error_messages={
            "required": "必须输入",
        }
    )

    #必须以clear起手,否则不能尽心检测
    def clean_user(self):
        import re
        val1 = self.cleaned_data.get("user")
        ret = re.findall(r'^_', val1)

        if not val1.isdigit():
            if ret:
                return val1
            else:
                raise ValidationError("必须以下划线开头")
        else:
            raise ValidationError("用户名不能全部为数字组成")

    def clean_pwd(self):
        val2=self.cleaned_data.get("pwd")
        if not val2.isdigit():
            return val2
        else:
            raise ValidationError("密码不能全部为数字!")

    def clean_phone(self):
        val3 = self.cleaned_data.get("phone")
        if val3.isdigit():
            if len(val3) != 11:
                raise ValidationError("亲,号码是11位!")
            else:
                return val3
        else:
            raise ValidationError("号码必须是数字!")

    def clean(self):
        pwd=self.cleaned_data.get("pwd")
        repeat_pwd=self.cleaned_data.get("repeat_pwd")
        if pwd==repeat_pwd:
            print("yes")
            return self.cleaned_data
        else:
            print("no")
            raise ValidationError("两次密码不一致!")




def login(request):
    if request.method == "POST":
        
        form_obj = LoginForm(request.POST)
        if form_obj.is_valid():
            user = request.POST.get("user")
            pwd  = request.POST.get("pwd")
            email = request.POST.get("email")
            phone = request.POST.get("phone")
            ret = models.user_info.objects.create(user=user,pwd=pwd,email=email,phone=phone)
            return HttpResponse("你好,欢迎回来!")
        else:

            ret = form_obj.errors.get("__all__")
            #{{form_obj.repwd}} < span > {{form_obj.errors.repwd.0}}{{form_obj.non_field_errors.0}} < / span >
            #还可以在前端直接传
            return render(request, "login.html", {"form_obj": form_obj,"ret":ret})
    
    
    form_obj = LoginForm()
    return render(request,"login.html",{"form_obj":form_obj})

import json
def user_check(request):
    response = {"is_reg": False}
    user = request.POST.get("user")
    ret = models.user_info.objects.filter(user=user)
    print(ret)
    if ret:
        response["is_reg"] = True
综合实例1

相关文章:

  • 2021-05-27
  • 2022-03-01
  • 2022-12-23
猜你喜欢
  • 2021-12-27
  • 2021-08-28
  • 2022-02-06
  • 2021-07-25
  • 2021-06-29
  • 2021-06-29
相关资源
相似解决方案