Django Forms元件,展示使用者輸入不合規的提示資訊,鉤子函式

冀未然發表於2024-03-25

Django Forms元件,展示使用者輸入不合規的提示資訊,鉤子函式

前戲:使用form表單,使用者輸入特定資訊,比如:金瓶,輸入框右側提示資訊,不使用Ajax。

前端程式碼:

<body>
<form action="" method="post">
    <p>username: <input type="text" name="username">
        <!--get請求觸發是,字典為空,span是行內標籤,行內標籤特性文字帶下取決於內部文字,此時不佔任何空間-->
        <span style="font-size: 15px">{{ back_dict.username }}</span>
    </p>

    <p>password: <input type="text" name="password">
        <span style="font-size: 15px">{{ back_dict.password }}</span>
    </p>

    <input type="submit" class="btn btn-danger">
</form>
</body>

後端程式碼邏輯:

def pl(request):
    back_dict = {'username': '', 'password': ''}
    """
    首先無論是POST還是GET請求,頁面都可獲得back_dict自定義字典
    只不過get請求來的時候,字典值是空的
    而post請求來之後,字典可能有值
    """
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        if '金瓶' in username:
            back_dict['username'] = '違規用詞'
        if len(password) < 3:
            back_dict['password'] = '密碼不可低於三位數'
    return render(request, 'pl.html', locals())

以上使用到的技術點。

  • 手動書寫前端獲取使用者資料的html程式碼 ---渲染html程式碼
  • 後端對使用者資料進行校驗 ---校驗資料
  • 對不符合要求的資料進行前端提示 ---展示提示資訊
    然而,form元件恰好也你能為我們做這些事。

注意: 資料校驗前端可有可無,但是後端一定要有,前後端結合校驗更好。

forms元件功能

  • 渲染html程式碼
  • 校驗資料
  • 展示提示資訊

forms基本使用

匯入模組,並自定義類。

from django import forms

class MyForm(forms.Form):
    # username欄位串型別最小3位,最大8位
    username = forms.CharField(min_length=3,max_length=8)
    # password欄位串型別最小3位,最大8位
    password = forms.CharField(min_length=3,max_length=8)
    # 郵箱欄位必須符合郵箱格式
    email = forms.EmailField()

校驗資料

  1. 測試環境,test.py,自己複製程式碼準備
  2. Pycharm自帶校驗資料功能

方法 描述
.is_valid() 判斷資料是否合法
.cleaned_data 檢視校驗透過資料
.errors 檢視未透過資料以及未透過原因

froms元件校驗資料只校驗類中出現的欄位,多傳不影響,多傳的欄位直接忽略
form_obj = views.MyForm({'username':'junjie','password':'123','email':'123@qq.com'})
form_obj.is_valid()
True
form_obj = views.MyForm({'username':'junjie','password':'123','email':'123@qq.com','like':'play'})
form_obj.is_valid()
True
form_obj.cleaned_data
{'username': 'junjie', 'password': '123', 'email': '123@qq.com'}
froms元件校驗資料 預設情況下,類中的所有欄位都必須傳值。
form_obj = views.MyForm({'username':'junjie','password':'123'})
form_obj.is_valid()
False
form_obj.cleaned_data
{'username': 'junjie', 'password': '123'}
form_obj.errors
{'email': ['This field is required.']}

渲染html

forms元件只會自動渲染獲取使用者輸入的標籤(input,select,radio,checkbox)

第一種方式

封裝程度太高,只適合本地測試使用。

views.py

from django import forms

class MyForm(forms.Form):
    # username欄位串型別最小3位,最大8位
    username = forms.CharField(min_length=3,max_length=8)
    # password欄位串型別最小3位,最大8位
    password = forms.CharField(min_length=3,max_length=8)
    # 郵箱欄位必須符合郵箱格式
    email = forms.EmailField()


def index(request):
    # 先產生一個空物件,空物件是關鍵
    form_obj = MyForm()
    # 直接將該空物件傳遞給html頁面
    return render(request,'index.html',locals())

前端

<form action="" method="post">
    <p>第一種渲染方式</p>
  <!--樣式多,但是封裝程度太高,適合本地測試-->
    {{ form_obj.as_p }}
		{{ form_obj.as_ul }}
    {{ form_obj.as_table }}
</form>



擴充套件性高,但是書寫程式碼過多,一般不用

<form action="" method="post">
    <p>第二種渲染方式</p>
    <p>{{ form_obj.username.label }}: {{ form_obj.username }}</p>
    <p>{{ form_obj.password.label }}: {{ form_obj.password }}</p>
    <p>{{ form_obj.email }}: {{ form_obj.email.label }}</p>
</form>

第三種渲染方式,推薦使用

    <p>第三種渲染方式</p>
    {% for form in form_obj %}
        <p>{{ form.label }}: {{ form }}</p>
    {% endfor %}

    <p></p>


總結:label屬性預設展示的是類中定義的欄位首字母與大寫的形式,也可以自己修改,直接給欄位物件加label屬性即可。

展示使用者輸入不合規的提示資訊

瀏覽器會自動校驗資料,但是前端的校驗弱不禁風,檢查中可以更改型別,那麼如何讓瀏覽器不做校驗由後端來做校驗?

<!--novalidate 告知前端不做校驗-->
<form action="" method="post" novalidate>
</form>
![](https://img2024.cnblogs.com/blog/1223896/202403/1223896-20240325085401845-612882431.png)

<form action="" method="post" novalidate>
    <p>第三種渲染方式</p>
    {% for form in form_obj %}
        <p>{{ form.label }}: {{ form }}</p>
        <!--{{ form.errors.0 }} 意味著這拿列表中第一個錯誤資訊,並且也不會生成ul標籤-->
        <span style="color: red">{{ form.errors.0 }}</span>
    {% endfor %}
    <input type="submit" class="btn btn-danger">
</form>


此時input輸入框最多輸入也被限制,並且點選提交按鈕,頁面重新整理但是input輸入框中的資訊也不會被重新整理,原由還是form元件的特殊之處,那麼為什麼會如此?

檢視後端邏輯程式碼。

def index(request):
    # 先產生一個空物件,空物件是關鍵
    form_obj = MyForm()
    if request.method == 'POST':
        # 獲取使用者資料並校驗
        """
        1.資料獲取繁瑣
        2.校驗資料需要構造成字典的格式傳入才可以
        ps:但是request.POST 可以看成一個字典
        """
        form_obj = MyForm(request.POST)
        # 判斷資料是否合法
        if form_obj.is_valid():
            # 合法運算元據庫,儲存資料
            return HttpResponse('恭喜,輸入資料全都合規')
        # 不合法 有錯誤
        # else:
            # 如何將錯誤資訊展示到前端?
    # 直接將該空物件傳遞給html頁面
    return render(request, 'index.html', locals())

  • forms元件展示錯物資訊必備的條件:
  • get請求和post請求傳給html頁面的物件變數名必須一樣
    forms元件當你的資料不合法的情況下,會儲存上次輸入的資料,讓你基於之前的結果進行修改,更加人性化
    到此forms元件錯誤資訊介紹完畢,接下補充知識。

方法 描述
label 欄位名
error_messages 自定義報錯資訊
initial 預設值
required forms元件中所有欄位預設必填(required)
required預設為Ture,可改為False
控制欄位是否必填
widget 更改input的type型別,以及增加bootstrap樣式
ValidationError 正則校驗,需要匯入模組
radio 單選框
Select 下拉框
checkbox 多選框

ValidationError,forms元件正則校驗,自上而下校驗。
from django.core.validators import RegexValidator

舉例ValidationError:

phone = forms.CharField(
    validators=[
        RegexValidator(r'^[0-9]+$', '請輸入數字'), # 先校驗這個正則,透過再校驗下面這個正則
        RegexValidator(r'^159[0-9]+$', '數字必須以159開頭')
    ]
)

後端邏輯程式碼error_messages:

from django import forms


class MyForm(forms.Form):
    # username欄位串型別最小3位,最大8位
    username = forms.CharField(min_length=3, max_length=8, label='使用者名稱',
                               # 不合符提醒自定義資訊
                               error_messages={
                                   'min_length=3':'使用者名稱最少3位',
                                   'max_length':'使用者名稱最大8位',
                                   # required沒有傳值
                                   'required':'使用者名稱不能為空'
                               })
    # password欄位串型別最小3位,最大8位
    password = forms.CharField(min_length=3, max_length=8, label='密碼',
                               error_messages={
                                   'min_length=3': '密碼最少3位',
                                   'max_length': '密碼最大8位',
                                   # required沒有傳值
                                   'required': '密碼不能為空'
                               }
                               )
    # 郵箱欄位必須符合郵箱格式
    email = forms.EmailField(label='郵箱',
                             error_messages={
                                 # 郵箱固定格式
                                 'invalid':'郵箱格式不能為空',
                                 # required沒有傳值
                                 'required': '郵箱不能為空'
                             }
                             )


def index(request):
    # 先產生一個空物件,空物件是關鍵
    form_obj = MyForm()
    if request.method == 'POST':
        # 獲取使用者資料並校驗
        """
        1.資料獲取繁瑣
        2.校驗資料需要構造成字典的格式傳入才可以
        ps:但是request.POST 可以看成一個字典
        """
        form_obj = MyForm(request.POST)
        # 判斷資料是否合法
        if form_obj.is_valid():
            # 合法運算元據庫,儲存資料
            return HttpResponse('恭喜,輸入資料全都合規')
        # 不合法 有錯誤
        # else:
            # 如何將錯誤資訊展示到前端?
    # 直接將該空物件傳遞給html頁面

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


舉例radio,select,checkbox

# radio 單選框
gender = forms.fields.ChoiceField(
    choices=((1, "男"), (2, "女"), (3, "保密")),
    label="性別",
    initial=3,
    widget=forms.widgets.RadioSelect()
)

# select 單選下拉框
hobby1 = forms.ChoiceField(
    choices=((1, "籃球"), (2, "足球"), (3, "雙色球"), ),
    label="愛好",
    initial=3,
    widget=forms.widgets.Select()
)

# select 多選下拉框
hobby2 = forms.MultipleChoiceField(
    choices=((1, "籃球"), (2, "足球"), (3, "雙色球"),),
    label="愛好",
    initial=[1, 3],
    widget=forms.widgets.SelectMultiple()
)

# 單選checkbox
keep = forms.ChoiceField(
    label="是否記住密碼",
    initial="checked",
    widget=forms.widgets.CheckboxInput()
)

# 多選checkbox
hobby = forms.MultipleChoiceField(
    choices=((1, "籃球"), (2, "足球"), (3, "雙色球"),),
    label="愛好",
    initial=[1, 3],
    widget=forms.widgets.CheckboxSelectMultiple()
)

鉤子函式(HOOK)

描述:在特點的節點自動觸發完成響應操作。在forms元件中類似於第二道關卡,讓我們自定義校驗規則。

在forms元件中有兩類鉤子:

  • 區域性鉤子
    當你需要給單個欄位增加校驗規則的時候可以使用
  • 全域性鉤子
    當你需要給多個欄位增加校驗規則的時候可以使用
第一道forms校驗透過會觸發自定義鉤子函式校驗 ,在類中定義。

舉例:

  1. 校驗使用者名稱中不能含有666 ---只校驗一個欄位,區域性鉤子
    2.校驗密碼和確認密碼是否一致 ---校驗多個欄位,全域性鉤子
class MyForm(forms.Form):
    username = forms.CharField(min_length=3, max_length=8, label='使用者名稱',
                               error_messages={'min_length': '最小三位數',
                                               'max_length': '最大三位數',
                                               'required': '不能為空'})

    password = forms.CharField(min_length=3, max_length=8, label='密碼',
                               error_messages={
                                   'min_length=3': '密碼最少3位',
                                   'max_length': '密碼最大8位',
                                   # required沒有傳值
                                   'required': '密碼不能為空'
                               }
                               )

    two_password = forms.CharField(min_length=3, max_length=8, label='二次確認密碼',
                                   error_messages={
                                       'min_length=3': '二次確認密碼最少3位',
                                       'max_length': '二次確認密碼最大8位',
                                       # required沒有傳值
                                       'required': '二次確認密碼不能為空'
                                   }
                                   )

    email = forms.EmailField(label='郵箱',
                             error_messages={
                                 # 郵箱固定格式
                                 'invalid': '郵箱格式不能為空',
                                 # required沒有傳值
                                 'required': '郵箱不能為空'
                             }
                             )

    # 鉤子函式
    # 區域性鉤子
    def clean_username(self):
        # 獲取到使用者名稱
        username = self.cleaned_data.get('username')
        if '666' in username:
            # 提示前端展示錯誤資訊
            self.add_error('username', '不能只有666')
        # 將鉤子函式勾出來的資料再放回去
        return username

    # 全域性鉤子
    def clean(self):
        password = self.cleaned_data.get('password')
        two_password = self.cleaned_data.get('two_password')
        if two_password != password:
            self.add_error('two_password','兩次密碼不一致')
        # 將鉤子函式勾出來的資料再放回去
        return self.cleaned_data

相關文章