0三、 forms組件

一、校驗字段功能

一、reg頁面準備

modelscss

from django.db import models

class UserInfo(models.Model):
    useranme = models.CharField(max_length=32)
    password = models.CharField(max_length=32)
    email = models.EmailField()
    telephone = models.CharField(max_length=32)

 

生成數據表html

C:\PycharmProjects\formsdemo>python manage.py makemigrations
C:\PycharmProjects\formsdemo>python manage.py migrate

 

主urlpython

from django.contrib import admin
from django.urls import path, re_path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    re_path(r'^', include(('app01.urls', 'app01')))
]

 

 

url數據庫

from django.urls import path, re_path, include
from app01 import views

urlpatterns = [
    re_path(r'reg/$', views.reg, name='reg'),
]

 

 

模板層django

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="" method="post">
    {% csrf_token %}
    <p>用戶名 <input type="text" name="user"></p>
    <p>密碼   <input type="password" name="pwd"></p>
    <p>確認密碼 <input type="password" name="_pwd"></p>
    <p>郵箱   <input type="text" name="email"></p>
    <p>手機號 <input type="text" name="tel"></p>
    <input type="submit" value="註冊">
</form>

</body>
</html>

 

 

viewbootstrap

from django.shortcuts import render, HttpResponse


def reg(request):
    if request.method == 'POST':
        print(request.POST)
        return HttpResponse('註冊成功')

    return render(request, 'reg.html')

 

 

<QueryDict: {'csrfmiddlewaretoken': ['5EwZsUEKRVj836bplmS03PVruttZhG'], 'user': ['alex'], 'pwd': ['123'], '_pwd': ['123'], 'email': ['123@qq.com'], 'tel': ['1234566778']}>

  

 

二、定義規則

 

from django import forms   # 導入forms組件


# 定義校驗規則
class UserForm(forms.Form):
    name = forms.CharField(min_length=4, max_length=10)
    email = forms.EmailField()
View Code

 

 

三、form.is_valid()

 

 

reg視圖代碼app

from django.shortcuts import render, HttpResponse

# Create your views here.

from django import forms   # 導入forms組件


# 定義校驗規則
class UserForm(forms.Form):
    name = forms.CharField(min_length=4, max_length=10)
    email = forms.EmailField()


def reg(request):
    if request.method == 'POST':

        # 1.form.is_valid()  是否經過驗證
        form = UserForm({'name': 'alex', 'email': '123@qq.com'})
        print(form.is_valid())      # True  返回布爾值

        form = UserForm({'name': 'a', 'email': '123'})
        print(form.is_valid())      # False

        form = UserForm({'name': 'alex', 'email': '123@qq.com', 'age': '33'})
        print(form.is_valid())      # True
        #
        form = UserForm({'name': 'alex', 'xxx': '123@qq.com'})
        print(form.is_valid())      # False

        form = UserForm({'name': 'a', 'email': '123', 'xxx': '123'})
        print(form.is_valid())      # False

        if form.is_valid():
            pass
        else:
            pass

        """
        forms組件只會校驗定義過的字段,
            定義的data,必須知足條件且存在  True
            多餘的字段,不影響
        """
        return HttpResponse('註冊成功')

    return render(request, 'reg.html')

 

 

 

四、form.cleaned_data:清洗過的數據   form.errors:報錯信息

 

from django.shortcuts import render, HttpResponse

# Create your views here.

from django import forms   # 導入forms組件


# 定義校驗規則
class UserForm(forms.Form):
    name = forms.CharField(min_length=4, max_length=10)
    email = forms.EmailField()


def reg(request):
    if request.method == 'POST':

        # 1.form.is_valid()  是否經過驗證
        form = UserForm({'name': 'alex', 'email': '123@qq.com'})
        print(form.is_valid())      # True  返回布爾值

        form = UserForm({'name': 'a', 'email': '123'})
        print(form.is_valid())      # False

        form = UserForm({'name': 'alex', 'email': '123@qq.com', 'age': '33'})
        print(form.is_valid())      # True
        #
        form = UserForm({'name': 'alex', 'xxx': '123@qq.com'})
        print(form.is_valid())      # False

        form = UserForm({'name': 'a', 'email': '123', 'xxx': '123'})
        print(form.is_valid())      # False


        # 2. form.cleaned_data
        #    form.errors
        if form.is_valid():
            print('cleaned_data1:', form.cleaned_data)
            print('errors1:', form.errors)
        else:
            print('cleaned_data2:', form.cleaned_data)
            print('errors2:', form.errors)

            # 取出error——msg
            print(form.errors.get("name"))
            print(type(form.errors.get("name")))  # ErrorList
            print(form.errors.get("name")[0])     # Ensure this value has at least 4 characters (it has 1).


        """
        if 全部字段校驗成功,則
            form.cleaned_data:  {'name': 'alex', 'email': '123@qq.com'}  只保留定義過的字段
            form.errors: 空

        if 校驗不成功,則
            form.cleaned_data:{'name': 'alex'}  只保留定義過的字段,
            form.errors:    <li>email<ul class="errorlist">  定義過的字段,未經過的信息

            (cleaned_data + errors 之和,一定是定義過的全部字段)
        """

        return HttpResponse('註冊成功')

    return render(request, 'reg.html')

 

 

(1)驗證經過ide

驗證字段函數

 

 

 

(2)驗證不經過post

 

  示例1:驗證字段

 

 

 

 

  示例2:驗證字段

 

 

 

 

五、取出 forms.error錯誤信息

 

 

 六、完整演示代碼

url

from django.urls import path, re_path, include
from app01 import views

urlpatterns = [
    re_path(r'reg_test/$', views.reg_test, name='reg_test'),
]

 

 

view

from django.shortcuts import render, HttpResponse

from django import forms   # 導入forms組件

# 定義校驗規則
class UserForm(forms.Form):
    name = forms.CharField(min_length=4, max_length=10)
    pwd = forms.CharField(min_length=4)
    _pwd = forms.CharField(min_length=4)
    email = forms.EmailField()
    tel = forms.CharField()



def reg_test(request):
    if request.method == "POST":
        form = UserForm(request.POST)   # from表單的name屬性值應該與forms組件字段名稱一致
        print(form)

        if form.is_valid():
            print(form.cleaned_data)
            return HttpResponse("註冊成功")
        else:
            print(form.cleaned_data)                # {'email': '123@qq.com', 'tel': 'a3456789'}
            print(form.errors)                      # <ul class="errorlist"><li>name<ul class="errorlist"><li>This fie

            print(type(form.errors))                # ErrorList
            print(form.errors.get('name'))          # <ul class="errorlist"><li>This field is required.</li></ul>
            print(type(form.errors.get('name')))    # ErrorList
            print(form.errors.get('name')[0])       # This field is required.
            return HttpResponse("註冊失敗")

    return render(request, 'reg.html')

 

 

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="" method="post">
    {% csrf_token %}
    <p>用戶名 <input type="text" name="user"></p>
    <p>密碼 <input type="password" name="pwd"></p>
    <p>確認密碼 <input type="password" name="_pwd"></p>
    <p>郵箱 <input type="text" name="email"></p>
    <p>手機號 <input type="text" name="tel"></p>
    <input type="submit" value="註冊">
</form>

</body>
</html>

 

注意點:

from表單的name屬性值應該與forms組件字段名稱一致

 

 

<tr><th><label for="id_name">Name:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="name" maxlength="10" minlength="4" required id="id_name" /></td></tr>
<tr><th><label for="id_pwd">Pwd:</label></th><td><ul class="errorlist"><li>Ensure this value has at least 4 characters (it has 3).</li></ul><input type="text" name="pwd" value="123" minlength="4" required id="id_pwd" /></td></tr>
<tr><th><label for="id__pwd"> pwd:</label></th><td><ul class="errorlist"><li>Ensure this value has at least 4 characters (it has 3).</li></ul><input type="text" name="_pwd" value="123" minlength="4" required id="id__pwd" /></td></tr>
<tr><th><label for="id_email">Email:</label></th><td><input type="email" name="email" value="123@qq.com" required id="id_email" /></td></tr>
<tr><th><label for="id_tel">Tel:</label></th><td><input type="text" name="tel" value="a3456789" required id="id_tel" /></td></tr>
UserForm(request.POST)

 

 

 

二、forms組件的渲染標籤功能

一、方式1: 用戶名 {{ form.name }}

views

from django.shortcuts import render, HttpResponse

from django import forms   # 導入forms組件


# 定義校驗規則
class UserForm(forms.Form):
    name = forms.CharField(min_length=4, max_length=10)
    pwd = forms.CharField(min_length=4)
    r_pwd = forms.CharField(min_length=4)
    email = forms.EmailField()
    tel = forms.CharField()


def reg_html(request):
    form = UserForm()

    return render(request, 'reg_html.html', locals())

 

reg.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h3>forms組件渲染方式1</h3>
<form action="" method="post">
    {% csrf_token %}
    <p>{{ form.name.label }} {{ form.name }}</p>
    <p>{{ form.pwd.label }} {{ form.pwd }}</p>
    <p>{{ form.r_pwd.label }} {{ form.r_pwd }}</p>
    <p>{{ form.email.label }} {{ form.email }}</p>
    <p>{{ form.tel.label }} {{ form.tel }}</p>
    <input type="submit" value="註冊">
</form>


</body>
</html>

 

 

 

原生標籤與渲染標籤的區別

 

 

 

 二、方式2:推薦

 views視圖

from django.shortcuts import render, HttpResponse

# Create your views here.

from django import forms   # 導入forms組件


# 定義校驗規則
class UserForm(forms.Form):
    name = forms.CharField(min_length=4, max_length=10, label="用戶名")
    pwd = forms.CharField(min_length=4, label="密碼")
    r_pwd = forms.CharField(min_length=4, label="確認密碼")
    email = forms.EmailField(label="郵箱")
    tel = forms.CharField(label="電話")


def reg_html(request):
    form = UserForm()

    return render(request, 'reg_html.html', locals())

 

 

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h3>forms組件渲染方式2:推薦</h3>
<form action="" method="post">
    {% csrf_token %}
    {% for field in form %}
        <p><label for="">{{ field.label }}:</label>{{ field }}</p>
    {% endfor %}

</form>


</body>
</html>

 

 

 

 

 三、方式3: {{ form.as_p }}  不靈活

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h3>forms組件渲染方式3 </h3>
<form action="" method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <hr>
    {{ form.as_ul }}
    <hr>
    {{ form.as_table }}
</form>

</body>
</html>

 

 

三、顯示error與重置輸入信息功能

 

views視圖

from django.shortcuts import render, HttpResponse

# Create your views here.

from django import forms   # 導入forms組件


# 定義校驗規則
class UserForm(forms.Form):
    name = forms.CharField(min_length=4, max_length=10, label="用戶名")
    pwd = forms.CharField(min_length=4, label="密碼")
    r_pwd = forms.CharField(min_length=4, label="確認密碼")
    email = forms.EmailField(label="郵箱")
    tel = forms.CharField(label="電話")


def reg_html(request):
    if request.method == 'POST':
        form = UserForm(request.POST)

        if form.is_valid():
            print(form.cleaned_data)        # 全部感受的字段以及對應的值
        else:
            print(form.cleaned_data)
            print(form.errors)               # ErrorDict: {"校驗錯誤的字段":["錯誤信息"]}
            print(form.errors.get('name'))   # ErrorList {'錯誤信息',}
            return render(request, 'reg_html.html', locals())

    form = UserForm()
    return render(request, 'reg_html.html', locals())

 

 

html

novalidate  當提交表單時不對錶單數據(輸入)進行驗證

  

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h3>forms組件渲染方式1</h3>
{#  novalidate  當提交表單時不對錶單數據(輸入)進行驗證#}
<form action="" method="post" novalidate>
    {% csrf_token %}
    <p>{{ form.name.label }} {{ form.name }} <span>{{ form.name.errors.0 }}</span></p>
    <p>{{ form.pwd.label }} {{ form.pwd }} <span>{{ form.pwd.errors.0 }}</span></p>
    <p>{{ form.r_pwd.label }} {{ form.r_pwd }} <span>{{ form.r_pwd.errors.0 }}</span></p>
    <p>{{ form.email.label }} {{ form.email }} <span>{{ form.email.errors.0 }}</span></p>
    <p>{{ form.tel.label }} {{ form.tel }} <span>{{ form.tel.errors.0 }}</span></p>
    <input type="submit" value="註冊">
</form>


</body>
</html>

 

 

四、forms組件的參數配置

 

 

 

 

 

forms組件 代碼

from django.shortcuts import render, HttpResponse

# Create your views here.

from django import forms  # 導入forms組件

from django.forms import widgets   # HTML Widget classes


# 定義校驗規則
class UserForm(forms.Form):
    name = forms.CharField(min_length=4,
                           max_length=10,
                           label="用戶名",
                           error_messages={'required': '該字段不能爲空', 'min_length': '不能少於4個字符'},
                           # widget=widgets.TextInput(),   # 定製Html控件
                           widget=widgets.TextInput(attrs={'class': 'form-control'}),  # html控件添加樣式
                           )
    pwd = forms.CharField(min_length=4,
                          label="密碼",
                          # widget=widgets.PasswordInput(),   # 定製Html控件
                          widget=widgets.PasswordInput(attrs={'class': 'form-control'}),
                          error_messages={'required': '該字段不能爲空'},
                          )
    r_pwd = forms.CharField(min_length=4,
                            label="確認密碼",
                            error_messages={'required': '該字段不能爲空'},
                            widget=widgets.PasswordInput(attrs={'class': 'form-control'}),
                            )
    email = forms.EmailField(label="郵箱",
                             error_messages={'required': '該字段不能爲空', 'invalid': '格式錯誤'},
                             widget=widgets.EmailInput(attrs={'class': 'form-control'})
                             )
    tel = forms.CharField(label="電話",
                          error_messages={'required': '該字段不能爲空 '},
                          widget=widgets.TextInput(attrs={'class': 'form-control'})
                          )


def reg_html(request):
    if request.method == 'POST':
        form = UserForm(request.POST)

        if form.is_valid():
            print(form.cleaned_data)  # 全部清洗的字段以及對應的值
        else:
            print(form.cleaned_data)
            print(form.errors)  # ErrorDict: {"校驗錯誤的字段":["錯誤信息"]}
            print(form.errors.get('name'))  # ErrorList {'錯誤信息',}
            return render(request, 'reg_html.html', locals())

    form = UserForm()
    return render(request, 'reg_html.html', locals())

 

 

加入bootstrap後的 html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"
          integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    <style type="text/css">
        span{
            color: red;
        }
    </style>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-md-6 col-lg-offset-3">
            <h3>forms組件渲染方式1</h3>
            {#  novalidate  當提交表單時不對錶單數據(輸入)進行驗證#}
            <form action="" method="post" novalidate>
                {% csrf_token %}
                <p>{{ form.name.label }} {{ form.name }} <span>{{ form.name.errors.0 }}</span></p>
                <p>{{ form.pwd.label }} {{ form.pwd }} <span>{{ form.pwd.errors.0 }}</span></p>
                <p>{{ form.r_pwd.label }} {{ form.r_pwd }} <span>{{ form.r_pwd.errors.0 }}</span></p>
                <p>{{ form.email.label }} {{ form.email }} <span>{{ form.email.errors.0 }}</span></p>
                <p>{{ form.tel.label }} {{ form.tel }} <span>{{ form.tel.errors.0 }}</span></p>
                <input type="submit" value="註冊">
            </form>
        </div>
    </div>
</div>

</body>
</html>

 

 

 

 

 

五、forms組件的局部鉤子

一、ValidationError:驗證錯誤

models

from django.db import models

class UserInfo(models.Model):
    name = models.CharField(max_length=32)
    pwd = models.CharField(max_length=32)
    email = models.EmailField()
    tel = models.CharField(max_length=32)

 

 

froms組件,如何進行驗證錯誤?

from app01.models import UserInfo       # 導入user表
from django.core.exceptions import ValidationError  # 導入驗證錯誤

from django import forms  # 導入forms組件
from django.forms import widgets   # HTML Widget classes


# 定義校驗規則
class UserForm(forms.Form):
    name = forms.CharField(min_length=4,
                           max_length=10,
                           label="用戶名",
                           error_messages={'required': '該字段不能爲空', 'min_length': '不能少於4個字符'},
                           # widget=widgets.TextInput(),   # 定製Html控件
                           widget=widgets.TextInput(attrs={'class': 'form-control'}),  # html控件添加樣式
                           )
    pwd = forms.CharField(min_length=4,
                          label="密碼",
                          # widget=widgets.PasswordInput(),   # 定製Html控件
                          widget=widgets.PasswordInput(attrs={'class': 'form-control'}),
                          error_messages={'required': '該字段不能爲空'},
                          )
    r_pwd = forms.CharField(min_length=4,
                            label="確認密碼",
                            error_messages={'required': '該字段不能爲空'},
                            widget=widgets.PasswordInput(attrs={'class': 'form-control'}),
                            )
    email = forms.EmailField(label="郵箱",
                             error_messages={'required': '該字段不能爲空', 'invalid': '格式錯誤'},
                             widget=widgets.EmailInput(attrs={'class': 'form-control'})
                             )
    tel = forms.CharField(label="電話",
                          error_messages={'required': '該字段不能爲空 '},
                          widget=widgets.TextInput(attrs={'class': 'form-control'})
                          )

    # 驗證用戶名
    def clean_name(self):
        val = self.cleaned_data.get("name")     # 獲取清洗後的字段中的name

        ret = UserInfo.objects.filter(name=val)  # 數據庫中的user
        if not ret:
            return ret
        else:
            raise ValidationError('該用戶已經註冊')    # 驗證錯誤

 

 

 

forms組件源碼

 

 

vies視圖中

def reg_html(request):
    if request.method == 'POST':
        form = UserForm(request.POST)

        if form.is_valid():
            print(form.cleaned_data)  # 全部清洗的字段以及對應的值
        else:
            print(form.cleaned_data)
            print(form.errors)  # ErrorDict: {"校驗錯誤的字段":["錯誤信息"]}
            print(form.errors.get('name'))  # ErrorList {'錯誤信息',}
            return render(request, 'reg_html.html', locals())

    form = UserForm()
    return render(request, 'reg_html.html', locals())

 

 模板層:不變

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"
          integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    <style type="text/css">
        span{
            color: red;
        }
    </style>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-md-6 col-lg-offset-3">
            <h3>forms組件渲染方式1</h3>
            {#  novalidate  當提交表單時不對錶單數據(輸入)進行驗證#}
            <form action="" method="post" novalidate>
                {% csrf_token %}
                <p>{{ form.name.label }} {{ form.name }} <span>{{ form.name.errors.0 }}</span></p>
                <p>{{ form.pwd.label }} {{ form.pwd }} <span>{{ form.pwd.errors.0 }}</span></p>
                <p>{{ form.r_pwd.label }} {{ form.r_pwd }} <span>{{ form.r_pwd.errors.0 }}</span></p>
                <p>{{ form.email.label }} {{ form.email }} <span>{{ form.email.errors.0 }}</span></p>
                <p>{{ form.tel.label }} {{ form.tel }} <span>{{ form.tel.errors.0 }}</span></p>
                <input type="submit" value="註冊">
            </form>
        </div>
    </div>
</div>

</body>
</html>
View Code

 

 

 

 二、校驗方法:clean_name 源碼

 

 

_clean_fields 方法的源碼
    def _clean_fields(self):
        for name, field in self.fields.items():     # {"name": name規則對象,"pwd": pwd規則對象...}
            # value_from_datadict() gets the data from the data dictionaries.
            # Each widget type knows how to retrieve its own data, because some
            # widgets split data over several HTML fields.
            if field.disabled:
                value = self.get_initial_for_field(field, name)
            else:
                value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
            try:
                if isinstance(field, FileField):
                    initial = self.get_initial_for_field(field, name)
                    value = field.clean(value, initial)
                else:
                    value = field.clean(value)      # 按照規則對象校驗傳遞進來的數據
                self.cleaned_data[name] = value
                if hasattr(self, 'clean_%s' % name):
                    value = getattr(self, 'clean_%s' % name)()
                    self.cleaned_data[name] = value         # 執行 def clean_name(self):
            except ValidationError as e:
                self.add_error(name, e)

 

 

三、局部鉤子函數如何校驗

一、forms代碼:校驗name,tel

from app01.models import UserInfo       # 導入user表
from django.core.exceptions import ValidationError  # 導入驗證錯誤

from django import forms  # 導入forms組件
from django.forms import widgets   # HTML Widget classes


# 定義校驗規則
class UserForm(forms.Form):
    name = forms.CharField(min_length=4,
                           max_length=10,
                           label="用戶名",
                           error_messages={'required': '該字段不能爲空', 'min_length': '不能少於4個字符'},
                           # widget=widgets.TextInput(),   # 定製Html控件
                           widget=widgets.TextInput(attrs={'class': 'form-control'}),  # html控件添加樣式
                           )
    pwd = forms.CharField(min_length=4,
                          label="密碼",
                          # widget=widgets.PasswordInput(),   # 定製Html控件
                          widget=widgets.PasswordInput(attrs={'class': 'form-control'}),
                          error_messages={'required': '該字段不能爲空'},
                          )
    r_pwd = forms.CharField(min_length=4,
                            label="確認密碼",
                            error_messages={'required': '該字段不能爲空'},
                            widget=widgets.PasswordInput(attrs={'class': 'form-control'}),
                            )
    email = forms.EmailField(label="郵箱",
                             error_messages={'required': '該字段不能爲空', 'invalid': '格式錯誤'},
                             widget=widgets.EmailInput(attrs={'class': 'form-control'})
                             )
    tel = forms.CharField(label="電話",
                          error_messages={'required': '該字段不能爲空 '},
                          widget=widgets.TextInput(attrs={'class': 'form-control'})
                          )

    # 驗證用戶名
    def clean_name(self):
        val = self.cleaned_data.get("name")     # 獲取清洗後的字段中的name

        ret = UserInfo.objects.filter(name=val)  # 數據庫中的user
        if not ret:
            return ret
        else:
            raise ValidationError('該用戶已經註冊')    # 驗證錯誤

    # 驗證手機號
    def clean_tel(self):
        val = self.cleaned_data.get("tel")
        if len(val) == 11:
            return val
        else:
            raise ValidationError("手機號格式錯誤")

 

 

示例1:校驗錯誤

 

 

 

 

示例2:校驗正確

 

 

 

 

四、全局鉤子校驗

一、全局鉤子clean 源碼剖析

 

 

二、直接覆蓋父類的clean方法,全局鉤子

froms組件繼承的是BaseFrom類,因此能夠直接覆蓋父類的clean方法,進行全局鉤子校驗

 

 

 

views視圖

from django.shortcuts import render, HttpResponse

from app01.models import UserInfo       # 導入user表
from django.core.exceptions import ValidationError  # 導入驗證錯誤

from django import forms  # 導入forms組件
from django.forms import widgets   # HTML Widget classes


# 定義校驗規則
class UserForm(forms.Form):
    name = forms.CharField(min_length=4,
                           max_length=10,
                           label="用戶名",
                           error_messages={'required': '該字段不能爲空', 'min_length': '不能少於4個字符'},
                           # widget=widgets.TextInput(),   # 定製Html控件
                           widget=widgets.TextInput(attrs={'class': 'form-control'}),  # html控件添加樣式
                           )
    pwd = forms.CharField(min_length=4,
                          label="密碼",
                          # widget=widgets.PasswordInput(),   # 定製Html控件
                          widget=widgets.PasswordInput(attrs={'class': 'form-control'}),
                          error_messages={'required': '該字段不能爲空'},
                          )
    r_pwd = forms.CharField(min_length=4,
                            label="確認密碼",
                            error_messages={'required': '該字段不能爲空'},
                            widget=widgets.PasswordInput(attrs={'class': 'form-control'}),
                            )
    email = forms.EmailField(label="郵箱",
                             error_messages={'required': '該字段不能爲空', 'invalid': '格式錯誤'},
                             widget=widgets.EmailInput(attrs={'class': 'form-control'})
                             )
    tel = forms.CharField(label="電話",
                          error_messages={'required': '該字段不能爲空 '},
                          widget=widgets.TextInput(attrs={'class': 'form-control'})
                          )
# 直接覆蓋父類的clean方法, 全局鉤子
    def clean(self):
        pwd = self.cleaned_data.get("pwd")
        r_pwd = self.cleaned_data.get("r_pwd")
        if pwd == r_pwd:
            return self.cleaned_data
        else:
            raise ValidationError("兩次密碼不一致")


def reg_html(request):
    if request.method == 'POST':
        form = UserForm(request.POST)

        if form.is_valid():
            print(form.cleaned_data)   # {"name": "alex", "pwd": "123",...}
        else:
            print(form.cleaned_data)        # # 全部清洗的字段以及對應的值
            print(form.errors)              # ErrorDict: {"校驗錯誤的字段":["錯誤信息"]}
            print(form.errors.get('name'))  # ErrorList {'錯誤信息',}

            # 獲取全局鉤子的error
            print("error:", form.errors.get("__all__")[0])
            errors = form.errors.get("__all__")

            return render(request, 'reg_html.html', locals())

    form = UserForm()
    return render(request, 'reg_html.html', locals())

 

 

 

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"
          integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    <style type="text/css">
        span{
            color: red;
        }
    </style>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-md-6 col-lg-offset-3">
            <h3>forms組件渲染方式1</h3>
            {#  novalidate  當提交表單時不對錶單數據(輸入)進行驗證#}
            <form action="" method="post" novalidate>
                {% csrf_token %}
                <p>{{ form.name.label }} {{ form.name }} <span>{{ form.name.errors.0 }}</span></p>
                <p>{{ form.pwd.label }} {{ form.pwd }} <span>{{ form.pwd.errors.0 }}</span></p>
{#                <p>{{ form.r_pwd.label }} {{ form.r_pwd }} <span>{{ form.r_pwd.errors.0 }}</span></p>  局部鉤子錯誤#}
                <p>{{ form.r_pwd.label }} {{ form.r_pwd }} <span class="pull-right error">{{ errors.0 }}</span></p>
                <p>{{ form.email.label }} {{ form.email }} <span>{{ form.email.errors.0 }}</span></p>
                <p>{{ form.tel.label }} {{ form.tel }} <span>{{ form.tel.errors.0 }}</span></p>
                <input type="submit" value="註冊">
            </form>
        </div>
    </div>
</div>

</body>
</html>

 

 

重點

# 接收全局鉤子error   errors.0
# bootstarp樣式   <span class="pull-right error">
<p>{{ form.r_pwd.label }} {{ form.r_pwd }} <span class="pull-right error">{{ errors.0 }}</span></p>

 

 

 

 

五、密碼,確認密碼,順序

# 每一個字段校驗完,在走全局方法

 好比,先判斷密碼是否正確,符合規則再判斷,兩次密碼是否一致

  

 

若是沒有pwd傳入進來的話,

 

 

 

    # 直接覆蓋父類的clean方法, 全局鉤子
    def clean(self):
        pwd = self.cleaned_data.get("pwd")
        r_pwd = self.cleaned_data.get("r_pwd")

        # 先判斷是否接受到pwd,r_pwd的值
        if pwd and r_pwd:
            if pwd == r_pwd:
                return self.cleaned_data
            else:
                raise ValidationError("兩次密碼不一致")
        else:
            return self.cleaned_data

 

 

 

六、form.is_valid 調用源碼

form.is_valid


def is_valid(self):
    """Return True if the form has no errors, or False otherwise."""
    return self.is_bound and not self.errors

def errors(self):
    """Return an ErrorDict for the data provided for the form."""
    if self._errors is None:
        self.full_clean()
    return self._errors


def full_clean(self):
    """
    Clean all of self.data and populate self._errors and self.cleaned_data.
    """
    self._errors = ErrorDict()
    if not self.is_bound:  # Stop further processing.
        return
    self.cleaned_data = {}
    # If the form is permitted to be empty, and none of the form data has
    # changed from the initial data, short circuit any validation.
    if self.empty_permitted and not self.has_changed():
        return

    self._clean_fields()     # 校驗每個字段
    self._clean_form()        # 校驗所有字段
    self._post_clean()

 

 

 

# 局部鉤子
    def _clean_fields(self):
        for name, field in self.fields.items():     # 校驗每個字段
            # value_from_datadict() gets the data from the data dictionaries.
            # Each widget type knows how to retrieve its own data, because some
            # widgets split data over several HTML fields.
            if field.disabled:
                value = self.get_initial_for_field(field, name)
            else:
                value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
            try:
                if isinstance(field, FileField):
                    initial = self.get_initial_for_field(field, name)
                    value = field.clean(value, initial)
                else:
                    value = field.clean(value)
                self.cleaned_data[name] = value
                if hasattr(self, 'clean_%s' % name):
                    value = getattr(self, 'clean_%s' % name)()
                    self.cleaned_data[name] = value
            except ValidationError as e:
                self.add_error(name, e)

 

 

# 全局鉤子調用順序
   
        def _clean_form(self):
            try:
                cleaned_data = self.clean()     # 全局鉤子
            except ValidationError as e:
                self.add_error(None, e)
            else:
                if cleaned_data is not None:
                    self.cleaned_data = cleaned_data
    
        def clean(self):
            """
            Hook for doing any extra form-wide cleaning after Field.clean() has been
            called on every field. Any ValidationError raised by this method will
            not be associated with a particular field; it will have a special-case
            association with the field named '__all__'.
            """
            return self.cleaned_data
        
        
        @html_safe
        class BaseForm:
            """
            The main implementation of all the Form logic. Note that this class is
            different than Form. See the comments by the Form class for more info. Any
            improvements to the form API should be made to this class, not to the Form
            class.
            """
            def clean(self):
                pass

 

 

 

七、總結:forms組件解耦,調用衝突

 

myforms.py  組件代碼

from app01.models import UserInfo       # 導入user表
from django.core.exceptions import ValidationError  # 導入驗證錯誤
from django import forms  # 導入forms組件
from django.forms import widgets   # HTML Widget classes


# 定義校驗規則
class UserForm(forms.Form):
    name = forms.CharField(min_length=4,
                           max_length=10,
                           label="用戶名",
                           error_messages={'required': '該字段不能爲空', 'min_length': '不能少於4個字符'},
                           # widget=widgets.TextInput(),   # 定製Html控件
                           widget=widgets.TextInput(attrs={'class': 'form-control'}),  # html控件添加樣式
                           )
    pwd = forms.CharField(min_length=4,
                          label="密碼",
                          # widget=widgets.PasswordInput(),   # 定製Html控件
                          widget=widgets.PasswordInput(attrs={'class': 'form-control'}),
                          error_messages={'required': '該字段不能爲空'},
                          )
    r_pwd = forms.CharField(min_length=4,
                            label="確認密碼",
                            error_messages={'required': '該字段不能爲空'},
                            widget=widgets.PasswordInput(attrs={'class': 'form-control'}),
                            )
    email = forms.EmailField(label="郵箱",
                             error_messages={'required': '該字段不能爲空', 'invalid': '格式錯誤'},
                             widget=widgets.EmailInput(attrs={'class': 'form-control'})
                             )
    tel = forms.CharField(label="電話",
                          error_messages={'required': '該字段不能爲空 '},
                          widget=widgets.TextInput(attrs={'class': 'form-control'})
                          )

    # 驗證用戶名
    def clean_name(self):
        val = self.cleaned_data.get("name")     # 獲取清洗後的字段中的name

        ret = UserInfo.objects.filter(name=val)  # 數據庫中的user
        if not ret:
            return ret
        else:
            raise ValidationError('該用戶已經註冊')    # 驗證錯誤

    # 驗證手機號
    def clean_tel(self):
        val = self.cleaned_data.get("tel")
        if len(val) == 11:
            return val
        else:
            raise ValidationError("手機號格式錯誤")

    # 直接覆蓋父類的clean方法, 全局鉤子
    def clean(self):
        pwd = self.cleaned_data.get("pwd")
        r_pwd = self.cleaned_data.get("r_pwd")

        # 先判斷是否接受到pwd,r_pwd的值
        if pwd and r_pwd:
            if pwd == r_pwd:
                return self.cleaned_data
            else:
                raise ValidationError("兩次密碼不一致")
        else:
            return self.cleaned_data

 

 

url

from django.urls import path, re_path, include
from app01 import views

urlpatterns = [
    re_path(r'reg_html/$', views.reg_html, name='reg_html'),
]

 

 

views視圖代碼

from django.shortcuts import render
from app01.myforms import *


def reg_html(request):
    if request.method == 'POST':
        form = UserForm(request.POST)

        if form.is_valid():
            print(form.cleaned_data)   # {"name": "alex", "pwd": "123",...}
        else:
            print(form.cleaned_data)        # # 全部清洗的字段以及對應的值
            print(form.errors)              # ErrorDict: {"校驗錯誤的字段":["錯誤信息"]}
            print(form.errors.get('name'))  # ErrorList {'錯誤信息',}

            # 獲取全局鉤子的error
            # print("error:", form.errors.get("__all__")[0])
            errors = form.errors.get("__all__")

            return render(request, 'reg_html.html', locals())

    form = UserForm()
    return render(request, 'reg_html.html', locals())

 

 

模板層

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"
          integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    <style type="text/css">
        span{
            color: red;
        }
    </style>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-md-6 col-lg-offset-3">
            <h3>forms組件渲染方式1</h3>
            {#  novalidate  當提交表單時不對錶單數據(輸入)進行驗證#}
            <form action="" method="post" novalidate>
                {% csrf_token %}
                <p>{{ form.name.label }} {{ form.name }} <span class="pull-right error">{{ form.name.errors.0 }}</span></p>
                <p>{{ form.pwd.label }} {{ form.pwd }} <span class="pull-right error">{{ form.pwd.errors.0 }}</span></p>
{# 局部鉤子錯誤  <p>{{ form.r_pwd.label }} {{ form.r_pwd }} <span>{{ form.r_pwd.errors.0 }}</span></p>  #}
{# 全局鉤子錯誤#}<p>{{ form.r_pwd.label }} {{ form.r_pwd }} <span class="pull-right error">{{ errors.0 }}</span></p>   
                <p>{{ form.email.label }} {{ form.email }} <span class="pull-right error">{{ form.email.errors.0 }}</span></p>
                <p>{{ form.tel.label }} {{ form.tel }} <span class="pull-right error">{{ form.tel.errors.0 }}</span></p>
                <input type="submit" value="註冊">
            </form>
        </div>
    </div>
</div>

</body>
</html>

 

相關文章
相關標籤/搜索