forms組件

来源:https://www.cnblogs.com/setcreed/archive/2019/12/03/11979697.html

[TOC] forms組件 先拋出一個需求: 手動書寫需求 views.py 這裡實現了三個功能: 手寫html頁面獲取用戶輸入信息 將數據傳入後端做數據校驗 如果有錯誤,展示錯誤信息 但是這個頁面手寫麻煩,輸入信息寫錯了,一刷新信息全沒了,很不友好!! 使用forms組件校驗數據 使用forms組 ...


forms組件

先拋出一個需求:

1.寫一個註冊功能,獲取用戶輸入的用戶名和密碼,提交到後端,後端做校驗
2.用戶名裡面不能含有敏感信息,給出相應的提示
3.如果密碼小於三位,就提示用戶

手動書寫需求

views.py

def register(request):
    errors = {'username':'', 'password':''}
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')

        if 'zf' in username:
            errors['username'] = '不能使用該字元'
        if len(password) < 4:
            errors['password'] = '密碼不能小於三位'

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

register.html

<form action="" method="post">
    <p>
        username:<input type="text" name="username">
        <span style="color: red">{{ errors.username }}</span>
    </p>
    <p>
        password:<input type="text" name="password">
        <span style="color: red">{{ errors.password }}</span>
    </p>
    <input type="submit">
</form>

這裡實現了三個功能:

  • 手寫html頁面獲取用戶輸入信息
  • 將數據傳入後端做數據校驗
  • 如果有錯誤,展示錯誤信息

但是這個頁面手寫麻煩,輸入信息寫錯了,一刷新信息全沒了,很不友好!!

使用forms組件校驗數據

使用forms組件首先要導入forms模塊, 寫這玩意類似於models

from django import forms

class MyForm(forms.Form):
    # username欄位 最多八位, 最少三位
    username = forms.CharField(max_length=8, min_length=3)
    # password欄位 最多八位, 最少三位
    password = forms.CharField(max_length=8, min_length=3)
    # email欄位  必須是郵箱格式
    email = forms.EmailField()

然後對數據進行校驗, 可以寫一個測試腳本,還可以使用pycharm左下角的Python Console功能,會自動搭建測試腳本

使用測試

校驗數據的方法:

  1. 給寫好的類 傳字典數據(待校驗的數據)

    form_obj = views.MyForm({'username':'cwz','password':'12','email':'123'})

  2. 如何查看校驗的數據是否合法

    form_obj.is_valid() 只有全部數據符合校驗規則才為True

  3. 如何查看不符合規則的欄位及錯誤的理由

    form_obj.errors

  4. 如何查看符合校驗規則的數據

    form_obj.cleaned_data

  5. forms組件中 定義的欄位預設都是必須傳值的 不能少傳

  6. forms組件只會校驗forms類中定義的欄位 如果你多傳了 不會有任何影響

forms組件渲染標簽

1. 方式一

forms組件只會幫你渲染用戶輸入的標簽,不會幫渲染提交按鈕標簽。

views.py

def index(request):
    # 渲染標簽,先生成一個空的form類的對象
    form_obj = MyForm()

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

前端頁面:

<p>forms組件渲染的方式1</p>
{{ form_obj.as_p }}
<br>
{{ form_obj.as_ul }}
<br>
{{ form_obj.as_table }}

效果:

總結:這種渲染標簽的方式封裝程度態高 不推薦使用 但是可以用在本地測試

2. 方式二

不推薦使用,比較麻煩

<p>forms組件渲染標簽方式2:</p>
{{ form_obj.username.label }}{{ form_obj.username }}
{{ form_obj.password.label }}{{ form_obj.password }}
{{ form_obj.email.label }}{{ form_obj.email }}

3.方式三

<p>forms組件渲染標簽方式3:</p>
{% for form in form_obj %}
    <p>{{ form.label }} {{ form }}</p>
{% endfor %}

若想要label標簽顯示中文,可以指定label標簽:

from django import forms

class MyForm(forms.Form):
    # username欄位 最多八位, 最少三位
    username = forms.CharField(max_length=8, min_length=3, label='用戶名')
    # password欄位 最多八位, 最少三位
    password = forms.CharField(max_length=8, min_length=3, label='密碼')
    # email欄位  必須是郵箱格式
    email = forms.EmailField(label='郵箱')

forms組件展示信息

<form action="" method="post">
    {% for form in form_obj %}
        <p>{{ form.label }} {{ form }}</p>
    {% endfor %}
    <input type="submit">
</form>

views.py

from django import forms

class MyForm(forms.Form):
    # username欄位 最多八位, 最少三位
    username = forms.CharField(max_length=8, min_length=3, label='用戶名')
    # password欄位 最多八位, 最少三位
    password = forms.CharField(max_length=8, min_length=3, label='密碼')
    # email欄位  必須是郵箱格式
    email = forms.EmailField(label='郵箱')

def index(request):
    # 渲染標簽,先生成一個空的forms類的對象
    form_obj = MyForm()

    if request.method == 'POST':
        form_obj = MyForm(request.POST)
        if form_obj.is_valid():
            print(form_obj.cleaned_data)
            return HttpResponse('數據正確')
        else:
            print(form_obj.errors)

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

這玩意是前端做的校驗

註意:

數據的校驗通常前後端都有,但是前端的校驗不堪一擊,可有可無;後端的校驗必須要有而且必須非常全面

在前端form表單加上一個參數(novalidate),就可以不做校驗:<form action="" method="post" novalidate>

前端錯誤信息展示寫法:

<form action="" method="post" novalidate>
    {% for form in form_obj %}
        <p>{{ form.label }} {{ form }}
            <span>{{ form.errors.0 }}</span>
        </p>

    {% endfor %}
    <input type="submit">
</form>

也支持中文顯示信息

from django import forms

class MyForm(forms.Form):
    # username欄位 最多八位, 最少三位
    username = forms.CharField(max_length=8, min_length=3, label='用戶名', error_messages={
        'max_length': '用戶名最長八位',
        'min_length': '用戶名最短三位',
        'required': '用戶名不能為空',
    })
    # password欄位 最多八位, 最少三位
    password = forms.CharField(max_length=8, min_length=3, label='密碼', error_messages={
        'max_length': '密碼最長八位',
        'min_length': '密碼最短三位',
        'required': '密碼不能為空',
    })
    # email欄位  必須是郵箱格式
    email = forms.EmailField(label='郵箱', error_messages={
        'required': '郵箱不能為空',
        'invalid': '郵箱格式不正確'
    })

form組件自定義校驗

RegexValidator驗證器

from django import forms
from django.core.validators import RegexValidator

class MyForm(forms.Form):
    # username欄位 最多八位, 最少三位
    username = forms.CharField(max_length=8, min_length=3, label='用戶名', error_messages={
        'max_length': '用戶名最長八位',
        'min_length': '用戶名最短三位',
        'required': '用戶名不能為空',
    })
    # password欄位 最多八位, 最少三位
    password = forms.CharField(max_length=8, min_length=3, label='密碼', error_messages={
        'max_length': '密碼最長八位',
        'min_length': '密碼最短三位',
        'required': '密碼不能為空',
    }, validators=[
        RegexValidator(r'^[0-9]+$', '請輸入數字'),
        RegexValidator(r'^139[0-9]+$', '數字必須要以139開頭')   # 可以添加多個正則表達式,從上往下校驗
    ]
    )

鉤子函數 (HOOK)

當你覺得上面的所有校驗還是不能滿足需求,可以考慮鉤子函數

全局鉤子

我們在Fom類中定義 clean() 方法,就能夠實現對欄位進行全局校驗。

class MyForm(forms.Form):
    # username欄位 最多八位, 最少三位
    username = forms.CharField(max_length=8, min_length=3, label='用戶名', error_messages={
        'max_length': '用戶名最長八位',
        'min_length': '用戶名最短三位',
        'required': '用戶名不能為空',
    })
    # password欄位 最多八位, 最少三位
    password = forms.CharField(max_length=8, min_length=3, label='密碼', error_messages={
        'max_length': '密碼最長八位',
        'min_length': '密碼最短三位',
        'required': '密碼不能為空',
    })

    re_password = forms.CharField(max_length=8, min_length=3, label='確認密碼', error_messages={
        'max_length': '確認密碼最長八位',
        'min_length': '確認密碼最短三位',
        'required': '確認密碼不能為空',
    })

    # 校驗密碼 確認密碼是否一致
    def clean(self):
        password = self.cleaned_data.get('password')
        re_password = self.cleaned_data.get('password')
        if not password == re_password:
            self.add_error('re_password', '兩次,密碼不一致')

        return self.cleaned_data

局部鉤子

我們在Fom類中定義 clean_欄位名() 方法,就能夠實現對特定欄位進行校驗。

class MyForm(forms.Form):
    # username欄位 最多八位, 最少三位
    username = forms.CharField(max_length=8, min_length=3, label='用戶名', error_messages={
        'max_length': '用戶名最長八位',
        'min_length': '用戶名最短三位',
        'required': '用戶名不能為空',
    })
    # password欄位 最多八位, 最少三位
    password = forms.CharField(max_length=8, min_length=3, label='密碼', error_messages={
        'max_length': '密碼最長八位',
        'min_length': '密碼最短三位',
        'required': '密碼不能為空',
    })

    re_password = forms.CharField(max_length=8, min_length=3, label='確認密碼', error_messages={
        'max_length': '確認密碼最長八位',
        'min_length': '確認密碼最短三位',
        'required': '確認密碼不能為空',
    })

    # 校驗用戶名中不能有666
    def clean_username(self):
        username = self.cleaned_data.get('username')
        if '666' in username:
            # 給username欄位添加錯誤信息
            self.add_error('username', '666是不存在的')
        # 將username返回出去
        return username

forms組件補充知識點

其他欄位參數

label input對應的提示信息

initial 預設值

required 預設為True 控制欄位是否必填

class MyForm(forms.Form):
    # username欄位 最多八位, 最少三位
    username = forms.CharField(max_length=8, min_length=3, label='用戶名', initial='預設值', 
        error_messages={
        'max_length': '用戶名最長八位',
        'min_length': '用戶名最短三位',
        'required': '用戶名不能為空',
                        }, required=False)

widget 給input框設置樣式及屬性

password = forms.CharField(max_length=8, min_length=3, label='密碼', error_messages={
        'max_length': '密碼最長八位',
        'min_length': '密碼最短三位',
        'required': '密碼不能為空',
    }, widget=forms.widgets.PasswordInput()  # 這個password欄位是密文的
username = forms.CharField(max_length=8, min_length=3, label='用戶名', initial='預設值',
                               error_messages={
                                   'max_length': '用戶名最長八位',
                                   'min_length': '用戶名最短三位',
                                   'required': '用戶名不能為空',
                               }, required=False,
                               widget=forms.widgets.TextInput({'class': 'form-control c1 c2', 'username': 'cwz'})
                               )

error_messages

重寫錯誤信息。

class LoginForm(forms.Form):
    username = forms.CharField(
        min_length=8,
        label="用戶名",
        initial="張三",
        error_messages={
            "required": "不能為空",
            "invalid": "格式錯誤",
            "min_length": "用戶名最短8位"
        }
    )
    pwd = forms.CharField(min_length=6, label="密碼")

password

class LoginForm(forms.Form):
    ...
    pwd = forms.CharField(
        min_length=6,
        label="密碼",
        widget=forms.widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True)
    )

radioSelect

單radio值為字元串

class LoginForm(forms.Form):
    username = forms.CharField(
        min_length=8,
        label="用戶名",
        initial="張三",
        error_messages={
            "required": "不能為空",
            "invalid": "格式錯誤",
            "min_length": "用戶名最短8位"
        }
    )
    pwd = forms.CharField(min_length=6, label="密碼")
    gender = forms.fields.ChoiceField(
        choices=((1, "男"), (2, "女"), (3, "保密")),
        label="性別",
        initial=3,
        widget=forms.widgets.RadioSelect()
    )

單選Select

class LoginForm(forms.Form):
    ...
    hobby = forms.ChoiceField(
        choices=((1, "籃球"), (2, "足球"), (3, "雙色球"), ),
        label="愛好",
        initial=3,
        widget=forms.widgets.Select()
    )

多選Select

class LoginForm(forms.Form):
    ...
    hobby = forms.MultipleChoiceField(
        choices=((1, "籃球"), (2, "足球"), (3, "雙色球"), ),
        label="愛好",
        initial=[1, 3],
        widget=forms.widgets.SelectMultiple()
    )

單選checkbox

class LoginForm(forms.Form):
    ...
    keep = forms.ChoiceField(
        label="是否記住密碼",
        initial="checked",
        widget=forms.widgets.CheckboxInput()
    )

多選checkbox

class LoginForm(forms.Form):
    ...
    hobby = forms.MultipleChoiceField(
        choices=((1, "籃球"), (2, "足球"), (3, "雙色球"),),
        label="愛好",
        initial=[1, 3],
        widget=forms.widgets.CheckboxSelectMultiple()
    )

choice欄位註意事項

在使用選擇標簽時,需要註意choices的選項可以配置從資料庫中獲取,但是由於是靜態欄位 獲取的值無法實時更新,需要重寫構造方法從而實現choice實時更新

方式一

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

 
class MyForm(Form):
 
    user = fields.ChoiceField(
        # choices=((1, '上海'), (2, '北京'),),
        initial=2,
        widget=widgets.Select
    )
 
    def __init__(self, *args, **kwargs):
        super(MyForm,self).__init__(*args, **kwargs)
        # self.fields['user'].choices = ((1, '上海'), (2, '北京'),)
        # 或
        self.fields['user'].choices = models.Classes.objects.all().values_list('id','caption')

方式二

from django import forms
from django.forms import fields
from django.forms import models as form_model

 
class FInfo(forms.Form):
    authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all())  # 多選
    # authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all())  # 單選

您的分享是我們最大的動力!

更多相關文章
  • Java抽象類: 抽象類特點 :抽象類除了不能實例化對象之外,類的其它功能依然存在,成員變數、成員方法和構造方法的訪問方式和普通類一樣。 由於抽象類不能實例化對象,所以抽象類必須被extends [抽象類]方式 繼承才能被使用。 抽象類表示的是一種繼承關係。 (總結就是:抽象類裡面設計跟普通類一樣, ...
  • lua中json和table的互轉,是我們在平時開發過程中經常用到的。比如: 在用lua編寫的伺服器中,如果客戶端發送json格式的數據,那麼在lua處理業務邏輯的時候,必然需要轉換成lua自己的數據結構,如table。此時,就會用到table和json格式的互轉。 在用lua編寫的伺服器中,如果我 ...
  • 先定義消息類型 orders.proto 在GOPATH創建目錄和編譯這個消息類型輸出到該目錄,包名是message 編寫go文件進行序列化和反序列化剛纔生成的包里的類型結構體數據 ...
  • swap(a,b) 用於交換a,b兩個變數的值; max(a,b) 返回a,b中的最大值; min(a,b) 返回a,b中的最小值; abs(x) 返回x的絕對值,x必須是整數; ...
  • ——日拱一卒,不期而至! 你好,我是彤哥,本篇是netty系列的第六篇。 簡介 上一章我們一起學習了Java NIO的核心組件Channel,它可以看作是實體與實體之間的連接,而且需要與Buffer交互,這一章我們就來學習一下Buffer的特性。 概念 Buffer用於與Channel交互時使用,通 ...
  • 前言 "上文" 我們介紹了JDK中的線程池框架 。我們知道,只要需要創建線程的情況下,即使是在單線程模式下,我們也要儘量使用 。即: 但是,在 "《阿裡巴巴Java開發手冊》" 中有一條 【強制】線程池不允許使用 Executors 去創建,而是通過 ThreadPoolExecutor 的方式,這 ...
  • PyCharm 是一種 Python IDE,可以幫助程式員節約時間,提高生產效率。那麼具體如何使用呢?本文從 PyCharm 安裝到插件、外部工具、專業版功能等進行了一一介紹,希望能夠幫助到大家。 機器之心之前也沒系統地介紹過 PyCharm,怎樣配置環境、怎樣 DeBug、怎樣同步 GitHub ...
  • 前言本文的文字及圖片來源於網路,僅供學習、交流使用,不具有任何商業用途,版權歸原作者所有,如有問題請及時聯繫我們以作處理。 作者:醍醐三葉 關於python的存儲問題, (1)由於python中萬物皆對象,所以python的存儲問題是對象的存儲問題,並且對於每個對象,python會分配一塊記憶體空間去 ...
一周排行
x