閱讀目錄
構建一個表單
導入模塊
from django import forms from django.forms import widgets from django.core.exceptions import ValidationError
創建form類
from django import forms from django.forms import widgets from django.core.exceptions import ValidationError import re from django.contrib.auth.models import User class LoginForm(forms.Form): # 字段名字(username)就是渲染后input標簽的name屬性 username = forms.CharField(min_length=2, max_length=8, strip=True, # 是否移除用戶輸入空白 # error_messages 為錯誤觸發的錯誤信息 error_messages={"required": "該字段不能為空", "min_length": "用戶名長度不能小於2", "max_length": "用戶名長度不能大於8"}, # 給input添加屬性 widget=widgets.TextInput(attrs={ "class": "form-control", "placeholder": "2-8 位中文/字母/下划線", "id": "inputname"})) password = forms.CharField(min_length=6,max_length=20, strip=True, error_messages={"required":"該字段不能為空", "min_length":"密碼長度不能小於6位", "max_length":"密碼長度不能大於20位"}, widget = widgets.PasswordInput(attrs={ "class":"form-control", "placeholder":"密碼需6-20個字符", "id":"inputPassword3"})) check_pwd = forms.CharField(min_length=6,max_length=20, strip=True, error_messages={"required":"該字段不能為空", "min_length":"密碼長度不能小於6位", "max_length":"密碼長度不能大於20位"}, widget = widgets.PasswordInput(attrs={ "class":"form-control", "placeholder":"請再次輸入密碼", "id":"inputPassword4"})) email = forms.EmailField(error_messages={'required': "郵箱不能為空", "invalid":"請輸入有效的郵箱地址"}, widget = widgets.EmailInput(attrs={ "class":"form-control", "placeholder":"請輸入郵箱", "id":"inputemail"}))
視圖
from .forms import LoginForm def form_reg(request): if request.method == "POST": login_form = LoginForm(request.POST) # 將數據傳給對應字段 綁定數據的表單實例 if login_form.is_valid(): # 判讀是否全部通過驗證 print("通過驗證") print(login_form.cleaned_data) # 保存全部通過驗證的表單數據 {'username': '周軍豪123', 'password': '961023hao'} username = login_form.cleaned_data.get("username") password = login_form.cleaned_data.get("password") User.objects.create_user(username=username, password=password) print("數據庫保存成功") return redirect("/log_in/") else: errors = login_form.errors # 字典類型,鍵是字段名,值是一個存着所有錯誤信息的列表 莫版中用{{ errors.字段名.0 }} # print(type(login_form.errors))# <class 'django.forms.utils.ErrorDict'> # login_form.errors={"user":["小於5位","不是數字"],"pwd":["",""]} error_all = errors.get("__all__") #全局鈎子的錯誤信息保存在了鍵是 __all__ 的值的列表中,在模版語言中用{{ error_all.0 }} print(error_all) return render(request, "form_reg.html", {"errors": errors, "error_all":error_all, "login_form": login_form}) else:
login_form = LoginForm() # form組件的實例對象 未綁定表單實例 GET請求時渲染出input標簽
return render(request, "form_reg.html", {"login_form": login_form})
模版
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <!-- 新 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css"> <style> .container{ margin-top: 100px; } </style> </head> <body> <div class="container"> <div class="row"> <div class="col-md-6"> <form action="/login/" method="post"> {% csrf_token %} <div class="form-group"> <label for="user">user</label> {{ login_form.user }} <span>{{ errors.user.0 }}</span> </div> <div class="form-group"> <label for="pwd">pwd</label> {{ login_form.pwd }} <span>{{ errors.pwd.0 }}</span> </div> <div class="form-group"> <label for="gender">gender</label> {{ login_form.gender }}<span>{{ error_all.0 }}</span> </div> <p>{{ login_form.usersss }}</p> <button type="submit" class="btn btn-default">Submit</button> </form> <hr>
{# <form action="">#} {# {{ login_form.as_p }}#} {# </form>#} </div> </div> </div> </body> </html>
Django Form 類詳解
綁定的和未綁定的表單實例
綁定的和未綁定的表單 之間的區別非常重要:
- 未綁定的表單沒有關聯的數據。當渲染給用戶時,它將為空或包含默認的值。
- 綁定的表單具有提交的數據,因此可以用來檢驗數據是否合法。如果渲染一個不合法的綁定的表單,它將包含內聯的錯誤信息,告訴用戶如何糾正數據。
字段詳解
Widgets
每個表單字段都有一個對應的Widget
類,它對應一個HTML 表單Widget
,例如<input type="text">
。
在大部分情況下,字段都具有一個合理的默認Widget。例如,默認情況下,CharField
具有一個TextInput Widget
,它在HTML 中生成一個<input type="text">
。
字段的數據
不管表單提交的是什么數據,一旦通過調用is_valid()
成功驗證(is_valid()
返回True
),驗證后的表單數據將位於form.cleaned_data
字典中。這些數據已經為你轉換好為Python 的類型。
注:此時,你依然可以從request.POST
中直接訪問到未驗證的數據,但是訪問驗證后的數據更好一些。
在上面的聯系表單示例中,is_married將是一個布爾值。類似地,IntegerField
和FloatField
字段分別將值轉換為Python 的int
和float
。
表單字段詳細參考:http://blog.csdn.net/qq_14898613/article/details/61617007
使用表單模版
表單渲染的選項
對於<label>/<input>
對,還有幾個輸出選項:
{{ form.as_table }}
以表格的形式將它們渲染在<tr>
標簽中{{ form.as_p }}
將它們渲染在<p>
標簽中{{ form.as_ul }}
將它們渲染在<li>
標簽中
注意,你必須自己提供<table>
或<ul>
元素。
{{ form.as_p }}
會渲染如下:

<form action=""> <p> <label for="id_username">Username:</label> <input id="id_username" maxlength="100" name="username" type="text" required=""> </p> <p> <label for="id_password">Password:</label> <input id="id_password" maxlength="100" name="password" placeholder="password" type="password" required=""> </p> <p> <label for="id_telephone">Telephone:</label> <input id="id_telephone" name="telephone" type="number" required=""> </p> <p> <label for="id_email">Email:</label> <input id="id_email" name="email" type="email" required=""> </p> <p> <label for="id_is_married">Is married:</label> <input id="id_is_married" name="is_married" type="checkbox"> </p> <input type="submit" value="注冊"> </form>
Form組件的鈎子
局部鈎子
def clean_username(self): # 函數名必須已clean_字段名的格式 user = self.cleaned_data.get("username") if not User.objects.filter(username=user): if not user.isdigit(): if re.findall(r"^[A-Za-z0-9_\-\u4e00-\u9fa5]+$",user): return user # 通過檢測,原數據返回 self.cleaned_data.get("username") else: raise ValidationError('用戶名存在非法字符') # 沒通過檢測拋出錯誤,必須用ValidationError else: raise ValidationError("用戶名不能為純數字") else: raise ValidationError("該用戶名已存在")
全局鈎子
def clean(self): # 必須命名為clean # 判斷是否都通過檢測,都不為None if self.cleaned_data.get("password") and self.cleaned_data.get("check_pwd"): if self.cleaned_data.get("password") == self.cleaned_data.get("check_pwd"): return self.cleaned_data # 如果兩次密碼相同,返回干凈的字典數據 else: raise ValidationError("輸入密碼不一致") # 沒通過檢測返回異常信息 else: return self.cleaned_data
form組件補充
1.Django內置字段

Field required=True, 是否允許為空 widget=None, HTML插件 label=None, 用於生成Label標簽或顯示內容 initial=None, 初始值 help_text='', 幫助信息(在標簽旁邊顯示) error_messages=None, 錯誤信息 {'required': '不能為空', 'invalid': '格式錯誤'} show_hidden_initial=False, 是否在當前插件后面再加一個隱藏的且具有默認值的插件(可用於檢驗兩次輸入是否一直) validators=[], 自定義驗證規則 localize=False, 是否支持本地化 disabled=False, 是否可以編輯 label_suffix=None Label內容后綴 CharField(Field) max_length=None, 最大長度 min_length=None, 最小長度 strip=True 是否移除用戶輸入空白 IntegerField(Field) max_value=None, 最大值 min_value=None, 最小值 FloatField(IntegerField) ... DecimalField(IntegerField) max_value=None, 最大值 min_value=None, 最小值 max_digits=None, 總長度 decimal_places=None, 小數位長度 BaseTemporalField(Field) input_formats=None 時間格式化 DateField(BaseTemporalField) 格式:2015-09-01 TimeField(BaseTemporalField) 格式:11:12 DateTimeField(BaseTemporalField)格式:2015-09-01 11:12 DurationField(Field) 時間間隔:%d %H:%M:%S.%f ... RegexField(CharField) regex, 自定制正則表達式 max_length=None, 最大長度 min_length=None, 最小長度 error_message=None, 忽略,錯誤信息使用 error_messages={'invalid': '...'} EmailField(CharField) ... FileField(Field) allow_empty_file=False 是否允許空文件 ImageField(FileField) ... 注:需要PIL模塊,pip3 install Pillow 以上兩個字典使用時,需要注意兩點: - form表單中 enctype="multipart/form-data" - view函數中 obj = MyForm(request.POST, request.FILES) URLField(Field) ... BooleanField(Field) ... NullBooleanField(BooleanField) ... ChoiceField(Field) ... choices=(), 選項,如:choices = ((0,'上海'),(1,'北京'),) required=True, 是否必填 widget=None, 插件,默認select插件 label=None, Label內容 initial=None, 初始值 help_text='', 幫助提示 ModelChoiceField(ChoiceField) ... django.forms.models.ModelChoiceField queryset, # 查詢數據庫中的數據 empty_label="---------", # 默認空顯示內容 to_field_name=None, # HTML中value的值對應的字段 limit_choices_to=None # ModelForm中對queryset二次篩選 ModelMultipleChoiceField(ModelChoiceField) ... django.forms.models.ModelMultipleChoiceField TypedChoiceField(ChoiceField) coerce = lambda val: val 對選中的值進行一次轉換 empty_value= '' 空值的默認值 MultipleChoiceField(ChoiceField) ... TypedMultipleChoiceField(MultipleChoiceField) coerce = lambda val: val 對選中的每一個值進行一次轉換 empty_value= '' 空值的默認值 ComboField(Field) fields=() 使用多個驗證,如下:即驗證最大長度20,又驗證郵箱格式 fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),]) MultiValueField(Field) PS: 抽象類,子類中可以實現聚合多個字典去匹配一個值,要配合MultiWidget使用 SplitDateTimeField(MultiValueField) input_date_formats=None, 格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y'] input_time_formats=None 格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M'] FilePathField(ChoiceField) 文件選項,目錄下文件顯示在頁面中 path, 文件夾路徑 match=None, 正則匹配 recursive=False, 遞歸下面的文件夾 allow_files=True, 允許文件 allow_folders=False, 允許文件夾 required=True, widget=None, label=None, initial=None, help_text='' GenericIPAddressField protocol='both', both,ipv4,ipv6支持的IP格式 unpack_ipv4=False 解析ipv4地址,如果是::ffff:192.0.2.1時候,可解析為192.0.2.1, PS:protocol必須為both才能啟用 SlugField(CharField) 數字,字母,下划線,減號(連字符) ... UUIDField(CharField) uuid類型 ...
2.Django內置插件

TextInput(Input)
NumberInput(TextInput)
EmailInput(TextInput)
URLInput(TextInput)
PasswordInput(TextInput)
HiddenInput(TextInput)
Textarea(Widget)
DateInput(DateTimeBaseInput)
DateTimeInput(DateTimeBaseInput)
TimeInput(DateTimeBaseInput)
CheckboxInput
Select
NullBooleanSelect
SelectMultiple
RadioSelect
CheckboxSelectMultiple
FileInput
ClearableFileInput
MultipleHiddenInput
SplitDateTimeWidget
SplitHiddenDateTimeWidget
SelectDateWidget
3.常用選擇插件

# 單radio,值為字符串 # user = fields.CharField( # initial=2, # widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),)) # ) # 單radio,值為字符串 # user = fields.ChoiceField( # choices=((1, '上海'), (2, '北京'),), # initial=2, # widget=widgets.RadioSelect # ) # 單select,值為字符串 # user = fields.CharField( # initial=2, # widget=widgets.Select(choices=((1,'上海'),(2,'北京'),)) # ) # 單select,值為字符串 # user = fields.ChoiceField( # choices=((1, '上海'), (2, '北京'),), # initial=2, # widget=widgets.Select # ) # 多選select,值為列表 # user = fields.MultipleChoiceField( # choices=((1,'上海'),(2,'北京'),), # initial=[1,], # widget=widgets.SelectMultiple # ) # 單checkbox # user = fields.CharField( # widget=widgets.CheckboxInput() # ) # 多選checkbox,值為列表 # user = fields.MultipleChoiceField( # initial=[2, ], # choices=((1, '上海'), (2, '北京'),), # widget=widgets.CheckboxSelectMultiple # )