Django Form組件

FORM 組件

概念

  內置的Django form組件操做更加簡單html

form組件的主要功能:

  • 生成頁面可用的HTML標籤
  • 對用戶提交的數據進行校驗
  • 保留上次輸入內容

普通的方式建立 form 表單

  在html文件中建立好form表單並作好排版,而後動態數據經過後臺函數提供前端

views.pygit

 1 def register(request):
 2     error_msg = ""
 3     if request.method == "POST":
 4         username = request.POST.get("name")
 5         pwd = request.POST.get("pwd")
 6         # 對註冊信息作校驗
 7         if len(username) < 6:
 8             # 用戶長度小於6位
 9             error_msg = "用戶名長度不能小於6位"
10         else:
11             # 將用戶名和密碼存到數據庫
12             return HttpResponse("註冊成功")
13     return render(request, "register.html", {"error_msg": error_msg})

login.html正則表達式

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>註冊頁面</title>
 6 </head>
 7 <body>
 8 <form action="/reg/" method="post">
 9     {% csrf_token %}
10     <p>
11         用戶名:
12         <input type="text" name="name">
13     </p>
14     <p>
15         密碼:
16         <input type="password" name="pwd">
17     </p>
18     <p>
19         <input type="submit" value="註冊">
20         <p style="color: red">{{ error_msg }}</p>
21     </p>
22 </form>
23 </body>
24 </html>

使用form組件實現註冊功能

  在後臺函數建立好form類實例化後和動態數據一塊兒傳到前端HTML文件,再由HTML文件排版數據庫

form.py
  (一般會將 form 表單的操做在 一個單獨的文件裏面寫 這樣和model.py同級便於區分)django

1 from django import forms
2 # 按照Django form組件的要求本身寫一個類
3 class RegForm(forms.Form):
4     name = forms.CharField(label="用戶名")
5     pwd = forms.CharField(label="密碼")

views.py框架

1 def register2(request):
2     form_obj = RegForm()
3     if request.method == "POST":
4         # 實例化form對象的時候,把post提交過來的數據直接傳進去
5         form_obj = RegForm(request.POST)
6         # 調用form_obj校驗數據的方法
7         if form_obj.is_valid():
8             return HttpResponse("註冊成功")
9     return render(request, "register2.html", {"form_obj": form_obj})

login2.htmlide

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>註冊2</title>
</head>
<body>
    <form action="/reg2/" method="post" novalidate autocomplete="off">
        {% csrf_token %}
        <div>
            <label for="{{ form_obj.name.id_for_label }}">{{ form_obj.name.label }}</label>
            {{ form_obj.name }} {{ form_obj.name.errors.0 }}
        </div>
        <div>
            <label for="{{ form_obj.pwd.id_for_label }}">{{ form_obj.pwd.label }}</label>
            {{ form_obj.pwd }} {{ form_obj.pwd.errors.0 }}
        </div>
        <div>
            <input type="submit" class="btn btn-success" value="註冊">
        </div>
    </form>
</body>
</html>

經常使用字段與插件

label

  標籤內顯示內容函數

class LoginForm(forms.Form):
  username = forms.CharField(
  min_length=8,
  label="用戶名",    # 顯示內容
  )

initial

初始值,input框裏面的初始值post

class LoginForm(forms.Form):
  username = forms.CharField(
  min_length=8,
  label="用戶名",
  initial="張三" # 設置默認值)

error_messages

重寫錯誤信息

內置字段格式:

  「錯誤類型」:「錯誤顯示信息」

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

widget

  插件,添加 各種的HTML 的標籤,並調整屬性樣式等操做,對每一種標籤除了經常使用的屬性之外都有不一樣的屬性值能夠設置

  •     attr={"k":"v"}                能夠添加自定義的字段。一般可用來添加 類 ,id 等 
  •     render_value = True   錯誤提交時原數據是否保留.
class LoginForm(forms.Form):
  pwd = forms.CharField(
  min_length=6,
  label="密碼",
  widget=forms.widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True)
  )

password

  密碼類型input標籤

  •     attr={"k":"v"}                能夠添加自動以的字段。一般可用來添加 類 id 等 
  •     render_value = True   錯誤提交時原數據是否保留.
class LoginForm(forms.Form):
  pwd = forms.CharField(
  min_length=6,
  label="密碼",
  widget=forms.widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True)
  )

單選 radioSelect

  •   choices=((num,"v"),((num,"v"),((num,"v"))    choice爲選項內容,num爲後臺提交數據標識,v爲選項數據內容 
  •        initial 初始選項值
class LoginForm(forms.Form):
  gender = forms.fields.ChoiceField(
  choices=((1, ""), (2, ""), (3, "保密")),
  label="性別",
  initial=3,
  widget=forms.widgets.RadioSelect()
  )    

多選Select

  •   choices=((num,"v"),((num,"v"),((num,"v"))    choice爲選項內容,num爲後臺提交數據標識,v爲選項數據內容 
  •        initial 初始選項值,多選的時候可用列表形式提交
class LoginForm(forms.Form):
  hobby = forms.fields.MultipleChoiceField(
  choices=((1, "籃球"), (2, "足球"), (3, "雙色球"), ),
  label="愛好",
  initial=[1, 3], 
  widget=forms.widgets.SelectMultiple()
  )    

單選checkbox

  •        initial 初始選項值,被選中爲 「checked」
class LoginForm(forms.Form):
  keep = forms.fields.ChoiceField(
  label="是否記住密碼",
  initial="checked",
  widget=forms.widgets.CheckboxInput()
  )    

多選checkbox

  •   choices=((num,"v"),((num,"v"),((num,"v"))    choice爲選項內容,num爲後臺提交數據標識,v爲選項數據內容 
  •        initial 初始選項值,多選的時候可用列表形式提交
class LoginForm(forms.Form):
  ...
  hobby = forms.fields.MultipleChoiceField(
  choices=((1, "籃球"), (2, "足球"), (3, "雙色球"),),
  label="愛好",
  initial=[1, 3],
  widget=forms.widgets.CheckboxSelectMultiple()
  )    

choice字段注意事項

  choices的選項能夠配置從數據庫中獲取,可是因爲是靜態字段 獲取的值沒法實時更新,須要重寫 構造方法 從而實現choice實時更新。
 方式一: 

    重寫 init 方法,在繼承父類的前提下從新在去數據庫查詢一次

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()) # 單選

所有的內置字段

  1 Field
  2     required=True,               是否容許爲空
  3     widget=None,                 HTML插件
  4     label=None,                  用於生成Label標籤或顯示內容
  5     initial=None,                初始值
  6     help_text='',                幫助信息(在標籤旁邊顯示)
  7     error_messages=None,         錯誤信息 {'required': '不能爲空', 'invalid': '格式錯誤'}
  8     validators=[],               自定義驗證規則
  9     localize=False,              是否支持本地化
 10     disabled=False,              是否能夠編輯
 11     label_suffix=None            Label內容後綴
 12  
 13  
 14 CharField(Field)
 15     max_length=None,             最大長度
 16     min_length=None,             最小長度
 17     strip=True                   是否移除用戶輸入空白
 18  
 19 IntegerField(Field)
 20     max_value=None,              最大值
 21     min_value=None,              最小值
 22  
 23 FloatField(IntegerField)
 24     ...
 25  
 26 DecimalField(IntegerField)
 27     max_value=None,              最大值
 28     min_value=None,              最小值
 29     max_digits=None,             總長度
 30     decimal_places=None,         小數位長度
 31  
 32 BaseTemporalField(Field)
 33     input_formats=None          時間格式化   
 34  
 35 DateField(BaseTemporalField)    格式:2015-09-01
 36 TimeField(BaseTemporalField)    格式:11:12
 37 DateTimeField(BaseTemporalField)格式:2015-09-01 11:12
 38  
 39 DurationField(Field)            時間間隔:%d %H:%M:%S.%f
 40     ...
 41  
 42 RegexField(CharField)
 43     regex,                      自定製正則表達式
 44     max_length=None,            最大長度
 45     min_length=None,            最小長度
 46     error_message=None,         忽略,錯誤信息使用 error_messages={'invalid': '...'}
 47  
 48 EmailField(CharField)      
 49     ...
 50  
 51 FileField(Field)
 52     allow_empty_file=False     是否容許空文件
 53  
 54 ImageField(FileField)      
 55     ...
 56     注:須要PIL模塊,pip3 install Pillow
 57     以上兩個字典使用時,須要注意兩點:
 58         - form表單中 enctype="multipart/form-data"
 59         - view函數中 obj = MyForm(request.POST, request.FILES)
 60  
 61 URLField(Field)
 62     ...
 63  
 64  
 65 BooleanField(Field)  
 66     ...
 67  
 68 NullBooleanField(BooleanField)
 69     ...
 70  
 71 ChoiceField(Field)
 72     ...
 73     choices=(),                選項,如:choices = ((0,'上海'),(1,'北京'),)
 74     required=True,             是否必填
 75     widget=None,               插件,默認select插件
 76     label=None,                Label內容
 77     initial=None,              初始值
 78     help_text='',              幫助提示
 79  
 80  
 81 ModelChoiceField(ChoiceField)
 82     ...                        django.forms.models.ModelChoiceField
 83     queryset,                  # 查詢數據庫中的數據
 84     empty_label="---------",   # 默認空顯示內容
 85     to_field_name=None,        # HTML中value的值對應的字段
 86     limit_choices_to=None      # ModelForm中對queryset二次篩選
 87      
 88 ModelMultipleChoiceField(ModelChoiceField)
 89     ...                        django.forms.models.ModelMultipleChoiceField
 90  
 91  
 92      
 93 TypedChoiceField(ChoiceField)
 94     coerce = lambda val: val   對選中的值進行一次轉換
 95     empty_value= ''            空值的默認值
 96  
 97 MultipleChoiceField(ChoiceField)
 98     ...
 99  
100 TypedMultipleChoiceField(MultipleChoiceField)
101     coerce = lambda val: val   對選中的每個值進行一次轉換
102     empty_value= ''            空值的默認值
103  
104 ComboField(Field)
105     fields=()                  使用多個驗證,以下:即驗證最大長度20,又驗證郵箱格式
106                                fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
107  
108 MultiValueField(Field)
109     PS: 抽象類,子類中能夠實現聚合多個字典去匹配一個值,要配合MultiWidget使用
110  
111 SplitDateTimeField(MultiValueField)
112     input_date_formats=None,   格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']
113     input_time_formats=None    格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
114  
115 FilePathField(ChoiceField)     文件選項,目錄下文件顯示在頁面中
116     path,                      文件夾路徑
117     match=None,                正則匹配
118     recursive=False,           遞歸下面的文件夾
119     allow_files=True,          容許文件
120     allow_folders=False,       容許文件夾
121     required=True,
122     widget=None,
123     label=None,
124     initial=None,
125     help_text=''
126  
127 GenericIPAddressField
128     protocol='both',           both,ipv4,ipv6支持的IP格式
129     unpack_ipv4=False          解析ipv4地址,若是是::ffff:192.0.2.1時候,可解析爲192.0.2.1, PS:protocol必須爲both才能啓用
130  
131 SlugField(CharField)           數字,字母,下劃線,減號(連字符)
132     ...
133  
134 UUIDField(CharField)           uuid類型
135 
136 Django Form內置字段
View Code

form 組件的標籤生成方式 

所有默認生成

  直接將 form 類中的全部標籤以默認的方式總體生成

    操縱更加簡單,可是默認會添加不少的沒必要要的屬性

    並且不方便控制form表單的總體樣式

{{ form.as_p }}

自寫框架,自動生成標籤

  本身寫form表單框架,可是標籤內容用form 組件來填充循環一個一個生成

    對於form表單的樣式能夠調節了,可是生成的標籤依舊不少沒必要要的屬性

<form action="/reg2/" method="post" novalidate autocomplete="off">
        {% csrf_token %}
        
     <div> <label for="{{ form_obj.name.id_for_label }}">{{ form_obj.name.label }}</label> {{ form_obj.name }} {{ form_obj.name.errors.0 }} </div>

<div> <label for="{{ form_obj.pwd.id_for_label }}">{{ form_obj.pwd.label }}</label> {{ form_obj.pwd }} {{ form_obj.pwd.errors.0 }} </div>

<div> <input type="submit" class="btn btn-success" value="註冊"> </div> </form>

徹底手寫

  徹底不用form組件的標籤生成,所有手動寫

    徹底控制了標籤的樣式自由

    再也不須要基於form組件的內置字段來控制樣式

<form action="/addbook/" method="post">
    {% csrf_token %}
    <p>名稱<input type="text" name="title"></p>
    <p>價格<input type="text" name="price"></p>
    <input type="submit">
    
</form>

  ps:

    可是我仍是想要用form 組件的 驗證功能則須要注意一點 : 本身寫的標籤的 「 name 」 屬性必定要和 form 組件要驗證的字段名字對的上

class BookForm(forms.Form):
    title = forms.CharField()
    price = forms.FloatField()


def addbook(request):
    if request.method == "POST":
        print(request.POST)
        form = BookForm(request.POST)
        if form.is_valid():
            print("cleaned_data", form.cleaned_data)
        else:
            print("errors", form.errors)
    form = BookForm()
    return render(request, "addbook.html", locals())

  詳解:

  面代碼中 BookForm 註冊的字段名字爲 「 title 」 以及 「 price 」

  那麼本身手寫的 標籤的 「 name 」 屬性必定要和這個對上才能夠

<form action="/addbook/" method="post">
    {% csrf_token %}
    <p>名稱<input type="text" name="title"></p>
    <p>價格<input type="text" name="price"></p>
    <input type="submit">
    
</form>

  在校驗的時候,

    若是 BookForm 中要求字段比 實際傳入的字段要少 ,會引起空數據的 error (至關於有數據沒拿到)

    若是 BookForm 中要求字段比 實際傳入的字段要多 , BookForm 對要求驗證字段驗證結束無錯誤後是不會處理多餘的字段的。

    最明顯的特徵爲 csrf_token 的值不會進行處理也不會報錯

重寫鉤子函數

 1 # 重寫全局的鉤子函數,對確認密碼作校驗
 2 from django.core.exceptions import ValidationError
 3 
 4 
 5 def clean(self):
 6     password = self.cleaned_data.get("password")
 7     re_password = self.cleaned_data.get("re_password")
 8     if re_password and re_password != password:
 9         self.add_error("re_password", ValidationError("兩次密碼不一致"))
10  return self.cleaned_data 11     
12 
13 
14     
15 # 重寫局部鉤子函數 對名字字段的敏感字符進行判斷
16 from django.core.exceptions import ValidationError
17 
18 
19 def clean_name(self):
20     value = self.cleaned_data.get("name")
21     if "金瓶mei" in value:
22         raiseValidationError("不符合社會主義核心價值觀!")
23return value

關於 form is_vaild() 的執行順序

  0. form is_vaild()

    1. 判斷是否有數據 以及 是否有錯誤 (是否有數據直接能夠判斷)

    2 . 進行錯誤信息的判斷 (默認的錯誤信息爲 none 定義在 init 中)       

    2.1 執行 full_clean()方法

        2.1.1  建立一個 保存錯誤信息的 空字典 ( self._error = ErroDict() )

          2.2.2  建立一個 保存校驗經過數據的 空字典 ( self.cleaned_data = {} )

      2.2 而後分別執行下面的三個方法

        2.2.1 _clean_fields()

          2.2.1.1  for 循環每一個字段 ( self.fields.items() ) 分別校驗 ( 利用的是內置的校驗規則 )

若是有錯誤 在 self._error[] 中 在 add_error 中能夠捕獲到 ValidationError 異常進行處理  (稍微有些廢話就隱藏把)

若是沒有報錯 在cleaned_date[] 中 加入已經經過校驗的字段

          2.2.1.2  for 循環結束後 進行一次反射 查詢是否有 clean_%s %name 的方法 進行調用後執行

若是有錯誤 在 self._error[] 中 在 add_error 中能夠捕獲到 ValidationError 異常進行處理   (稍微有些廢話就隱藏把)

若是沒有報錯 在cleaned_date[] 中 加入已經經過校驗的字段

            即 這個 clean_%s 的方法爲一個鉤子函數 此鉤子能夠幫咱們解決什麼問題呢?
 這是個局部變量的鉤子 能夠對局部變量內部進行必定程度的操做 好比對變量的值進行操做

        2.2.2   _clean_form()

            調用對象的 .clean()方法,默認的繼承的 .clean() 是什麼都不作的

            即 .clean() 爲一個全局的鉤子 能夠對全部的變量進行操做 好比兩個變量的對比等

所以能夠利用這個clean方法進行 重寫 自定義想要的校驗操做

        2.2.3 post_clean()



    經過上面的流程能夠發現.不管是使用全局鉤子仍是局部鉤子都是對已經校驗經過的數據進行操做
    便是說 在調用 def clean_name(self): 或者 def clean(self): 的時候
      self.cleaned_data 裏面已經裝好了校驗經過的數據對象

    在調用 def clean(self):           經過get("name") 也能夠拿到全部的變量對象
    在調用 def clean_name(self):        經過get("name") 也能夠拿到當前的局部變量對象

    經過後面的流程也發現這兩個函數都要有返回值

      def clean(self):       須要返回全局的 self.cleaned_data

      ddef clean_name(self):    須要返回被處理的局部變量 value 

相關文章
相關標籤/搜索