知識儲備:HTML表單form學習
表單,在前端頁面中屬於最常見的一個東西了。基本上網站信息的提交都用到了表單,所以下面來學習Django中優雅的表單系統:Form
表單的主要作用是在網頁上提供一個圖形用戶頁面,用作采集和提供用戶輸入數據。
表單的基本結構: <form></form>
1,from表單常用屬性
- action :表單提交的服務器地址,也就是服務器接收表單數據的url地址
- method:表單提交數據的方法(一般為get/post)
- name:最好是name屬性的唯一性
- enctype:表單數據提交時使用的編碼類型,默認使用"pplication/x-www-form-urlencoded",如果使用post請求,則請求頭中的content-type指定值就是該值。如果表單中有上傳文件,編碼需要使用"multipart/form-data"類型才能完成傳遞文件數據。
1.1 提交方式 get和post
get:使用URL傳參:http://服務器地址?name1 = value&name2=value2(?表示傳遞參數,?后面采用name=value的形式傳遞,多個參數之間,用&鏈接)URL傳參不安全,所有信息可在地址欄看到,並且可以通過地址欄隨機傳遞其他數據。URL傳遞數據量有限,只能傳遞少量數據。
post:使用HTTP請求傳遞數據。URL地址欄不可見,比較安全。且傳遞數據量沒有限制。
表單提交中中get和post方式的區別
- 1,get是從服務器獲取數據,post是向服務器傳送數據
- 2,get安全性非常低,post安全性非常高
- 3,get傳送的數據量較小,不能大於2kb,post傳送的數據量較大,一般被默認為不受限制。但是理論上,IIS4中最大量為80KB,IIS5中為100KB。
- 4,對於get方式,服務器端用request.QueryString獲取變量的值,對於post方式,服務器端用Request.Form獲取提交的數據。
- 5,get請求不用添加{% csrf_token %},也不會報csrftoken的錯
- 6,post請求的話,就需要添加{ % csrf_token %}標簽,而且需要使用 $.ajax()方法,將token傳遞到服務端。
1.2 瀏覽器提交表單時,會執行如下步驟
- 1,識別出表單中表單元素的有效項,作為提交項
- 2,構建出一個表單數據集
- 3,根據form表單中的enctype屬性的值作為content-type對數據進行編碼
- 4,根據form表單中的action屬性和method屬性向指定的地址發送數據
2,input標簽
input標簽是輸入框,是表單中最重要的部分。
2.1 表單的type屬性:
<form action="外部鏈接路徑".method="get/post".name="#"> <input type="text">輸入文本框 <input type="password">輸入密碼框 <input type="button">輸入按鈕 <input type="reset">重置 <input type="submit">提交 <input type="file">文件 <input type="checkbox">多選框 <input type="checkbox" checked>代表多選框默認選擇項 <input type="radio">單選框,注意name需一樣 <input type="date">時間 <input type="checkbox">多選框
name:是指名字,因為提交的是鍵值對,所以必須要指定名字,否則無法提交,即使提交了也沒有意義。
value:文本框的內容,一般用在不能輸入的類型中,如改變按鈕的名字等。
placeholder:占位內容,通常用於顯示
readonly:只讀模式,設置后無法修改輸入框的內容
disabled:禁用狀態
size:由於輸入框是單行的,所以只能設置寬度
maxlength:限制輸入框最大輸入的字符個數
2.1 表單提交方式
開發中表單提交是很常見的,表單的提交方式也有很多種。
1,使用submit按鈕提交表單
<input type="submit" value="提交">
2,使用button按鈕提交表單
<input type="button" value="提交">
3,使用js進行表單提交,將form表單進行標記,將form表單中的某個元素設置成點擊事件,點擊時候調用js函數,再用JS。
$("#id").submit()
3,label 標簽—— for 屬性
label元素不會向用戶呈現任何特殊效果。不過,它為鼠標用戶改進了可用性。如果您在label元素內點擊文本,就會觸發此控件。也就是說,當用戶選擇該標簽時,瀏覽器就會自動將焦點轉到和標簽相關的表單控件上。
<label> 標簽的for屬性應當與相關元素的id屬性相同
3.1 實例
帶有兩個輸入字段和相關標記的簡單HTML表單:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <table> <tr> <td><label for="username">用戶名: </label></td> <td><input type="text" name="username" id="username"></td> </tr> <tr> <td><label for="username">密碼: </label></td> <td><input type="password" name="password" id="password"></td> </tr> <tr> <td><label for="repassword">密碼確認: </label></td> <td><input type="password" name="password" id="repassword"></td> </tr> <tr> <td><label for="_basketball">愛好: </label></td> <td> <label><input type="checkbox" value="basketball" name="'hobby" id="_basketball">basketball</label> <label><input type="checkbox" value="football" name="'hobby" id="_basketball">football</label> <label><input type="checkbox" value="skating" name="'hobby" id="_basketball">skating</label> </td> </tr> <tr> <td><label for="_boy">性別:</label></td> <td> <label><input type="radio" value="boy" name="sex" id="_boy">boy</label> <label><input type="radio" value="girl" name="sex" >girl</label> </td> </tr> <tr> <td><label for="email">郵箱:</label></td> <td><input type="text" name="email" id="email"></td> </tr> <tr> <td><label for="address">住址:</label></td> <td><input type="text" name="address" id="address"></td> </tr> </table> </body> </html>
4,Form表單名的功能
- 自動生成HTML表單元素
- 檢查表單數據的合法性
- 回顯功能(驗證錯誤,輸入數據不會被清空)
- 數據類型轉換(轉換成相應的python類型)
表單提交數據就是由HTML表單向后台傳遞信息,后台通過request.GET() 或者request.POST()獲取。
Django:表單字段和插件widgets
一,Django內建常用字段
字段類型的作用:
- 決定數據庫中對應列的數據類型(例如:INTEGER ,VARCHAR,TEXT)
- HTML中對應的表單標簽的類型,例如 <input type= "text" />
- 在admin后台和自動生成的表單中最小的數據驗證需求
Django內置了許多字段類型,他們都位於django.db.models中,例如models.CharField 。這些類型基本滿足需求。如果還不夠你也可以自定義字段。
class BooleanField(**kwargs)
- 默認的Widget:CheckboxInput
- 空值:False
- 規范化為:Python 的True 或 False。
- 如果字段帶有required=True,驗證值是否為True(例如復選框被勾上)。
- 錯誤信息的鍵:required
class CharField(**kwargs)
- 默認的Widget:TextInput
- 空值:’ ‘(一個空字符串)
- 規范化為:一個Unicode 對象。
- 如果提供,驗證max_length 或min_length。 否則,所有的輸入都是合法的。
- 錯誤信息的鍵:required, max_length, min_length
- 可選參數:max_length, min_length
class ChoiceField(**kwargs)
- 默認的Widget:Select
- 空值:”(一個空字符串)
- 規范化為:一個Unicode 對象。
- 驗證給定的值在選項列表中存在。
- 錯誤信息的鍵:required, invalid_choice
- 可選參數:choices
class TypedChoiceField(**kwargs)
- 默認的Widget:Select
- 空值:empty_value
- 規范化為:coerce 參數類型的值。
- 驗證給定的值在選項列表中存在並且可以被強制轉換。
- 錯誤信息的鍵:required, invalid_choice
- 可選參數:coerce,empty_value
class DateField(**kwargs)
- 默認的Widget:DateInput
- 空值:None
- 規范化為:一個Python datetime.date 對象。
- 驗證給出的值是一個datetime.date、datetime.datetime 或指定日期格式的字符串。
- 錯誤信息的鍵:required, invalid
- 可選參數:input_formats
class DateTimeField(**kwargs)
- 默認的Widget:DateTimeInput
- 空值:None
- 規范化為:一個Python datetime.datetime 對象。
- 驗證給出的值是一個datetime.date、datetime.datetime 或指定日期格式的字符串。
- 錯誤信息的鍵:required, invalid
- 可選參數:input_formats
class DecimalField(**kwargs)
- 默認的Widget:當Field.localize 是False 時為NumberInput,否則為TextInput。
- 空值:None
- 規范化為:一個Python decimal。
- 驗證給定的值為一個十進制數。忽略前導和尾隨的空白。
- 錯誤信息的鍵:required, invalid, max_value, min_value, max_digits, max_decimal_places, max_whole_digits
- 四個可選的參數:max_value,min_value,max_digits,decimal_places
class DurationField(**kwargs)
- 默認的Widget:TextInput
- 空值:None
- 規范化為:一個Python timedelta。
- 驗證給出的值是一個字符串,而可以給轉換為timedelta。
- 錯誤信息的鍵:required, invalid.
class EmailField(**kwargs)
- 默認的Widget:EmailInput
- 空值:”(一個空字符串)
- 規范化為:一個Unicode 對象。
- 驗證給出的值是一個合法的郵件地址,使用一個適度復雜的正則表達式。
- 錯誤信息的鍵:required, invalid
class FileField(**kwargs)
- 默認的Widget:ClearableFileInput
- 空值:None
- 規范化為:一個UploadedFile 對象,它封裝文件內容和文件名為一個單獨的對象。
- 可以驗證非空的文件數據已經綁定到表單。
- 誤信息的鍵:required, invalid, missing, empty, max_length
class FilePathField(**kwargs)
- 默認的Widget:Select
- 空值:None
- 規范化為:一個Unicode 對象。
- 驗證選擇的選項在選項列表中存在。
- 錯誤信息的鍵:required, invalid_choice
- 它接受三個額外的參數;只有path 是必需的:
- path,你想要列出的目錄的絕對路徑。這個目錄必須存在。
recursive,如果為False(默認值),只用直接位於path 下的文件或目錄作為選項。如果為True,將遞歸訪問這個目錄,其所有的子目錄和文件都將作為選項。
match,正則表達式表示的一個模式;只有匹配這個表達式的名稱才允許作為選項。
allow_files,可選。為True 或False。默認為True。表示是否應該包含指定位置的文件。它和allow_folders 必須有一個為True。
allow_folders,可選。為True 或False。 默認為False。表示是否應該包含指定位置的目錄。 它和allow_files 必須有一個為True。
class FloatField(**kwargs)
- 默認的Widget:當 Field.localize 是False 時為NumberInput,否則為TextInput。
- 空值:None
- 規范化為:一個Float 對象。
- 驗證給出的值是一個浮點數。和Python 的float() 函數一樣,允許前導和尾隨的空白符。
- 錯誤信息的鍵:required, invalid, max_value, min_value
class ImageField(**kwargs)
- 默認的Widget:ClearableFileInput
- 空值:None
- 規范化為: An UploadedFile object that wraps the file content and file name into a single object.
- 驗證文件數據已綁定到表單,並且該文件具有Pillow理解的圖像格式。
- 錯誤信息的鍵:required, invalid, missing, empty, invalid_image
class IntegerField(**kwargs)
- 默認的Widget:當Field.localize 是False 時為NumberInput,否則為TextInput。
- 空值:None
- 規范化為:一個Python 整數或長整數。
- 驗證給定值是一個整數。允許前導和尾隨空格,如Python的int()函數。
- 錯誤信息的鍵:required, invalid, max_value, min_value
- 可選參數:max_value,min_value
class GenericIPAddressField(**kwargs)
- 包含IPv4或IPv6地址的字段。
- 默認的Widget:TextInput
- 空值:”(一個空字符串)
- 規范化為:一個Unicode 對象。 IPv6地址如下所述進行歸一化。
- 驗證給定值是有效的IP地址。
- 錯誤信息的鍵:required, invalid
- 可選參數:protocol,unpack_ipv4
class MultipleChoiceField(**kwargs)
- 默認的Widget:SelectMultiple
- 空值:[](一個空列表)
- 規范化為:一個Unicode 對象列表。
- 驗證給定值列表中的每個值都存在於選擇列表中。
- 錯誤信息的鍵:required, invalid_choice, invalid_list
class TypedMultipleChoiceField(**kwargs)
就像MultipleChoiceField,除了TypedMultipleChoiceField需要兩個額外的參數,coerce和empty_value。
- 默認的Widget:SelectMultiple
- 空值:empty_value
- 規范化為:coerce參數提供的類型值列表。
- 驗證給定值存在於選項列表中並且可以強制。
- 錯誤信息的鍵:required, invalid_choice
class NullBooleanField(**kwargs)
- 默認的Widget:NullBooleanSelect
- 空值:None
- 規范化為:一個Python True, False 或None 值。
- 不驗證任何內容(即,它從不引發ValidationError)。
class RegexField(**kwargs)
- 默認的Widget:TextInput
- 空值:”(一個空字符串)
- 規范化為:一個Unicode對象
- 驗證給定值與某個正則表達式匹配。
- 錯誤信息的鍵:required, invalid
class SlugField(**kwargs)
- 默認的Widget:TextInput
- 空值:None
- 規范化為:一個Python 的datetime.time 對象。
- 驗證給定值是datetime.time或以特定時間格式格式化的字符串。
- 錯誤信息的鍵:required, invalid
class TimeField(**kwargs)
- 默認的Widget:TextInput
- 空值:None
- 規范化為:一個Python 的datetime.time 對象。
- 驗證給定值是datetime.time或以特定時間格式格式化的字符串。
- 錯誤信息的鍵:required, invalid
class URLField(**kwargs)
- 默認的Widget:URLInput
- 空值:”(一個空字符串)
- 規范化為:一個Unicode 對象。
- 驗證給定值是有效的URL。
- 錯誤信息的鍵:required, invalid
class UUIDField(**kwargs)
- 默認的Widget:TextInput
- 空值:”(一個空字符串)
- 規范化為:一個UUID 對象。
- 錯誤信息的鍵:required, invalid
- 復雜點的內建Field類
class ComboField(**kwargs)
- 默認的Widget:TextInput
- 空值:”(一個空字符串)
- 規范化為:一個Unicode 對象。
- 根據指定為ComboField的參數的每個字段驗證給定值。
- 錯誤信息的鍵:required, invalid
class MultiValueField(fields=(), **kwargs)
- 默認的Widget:TextInput
- 空值:”(一個空字符串)
- 規范化為:子類的compress方法返回的類型。
- 針對指定為MultiValueField的參數的每個字段驗證給定值。
- 錯誤信息的鍵:required, invalid, incomplete
class SplitDateTimeField(**kwargs)
- 默認的Widget:SplitDateTimeWidget
- 空值:None
- 規范化為:一個Python datetime.datetime 對象。
- 驗證給定的值是datetime.datetime或以特定日期時間格式格式化的字符串。
- 錯誤信息的鍵:required, invalid, invalid_date, invalid_time
- 處理關系的字段
兩個字段可用於表示模型之間的關系:ModelChoiceField和ModelMultipleChoiceField。這兩個字段都需要單個queryset參數,用於創建字段的選擇。在表單驗證時,這些字段將把一個模型對象(在ModelChoiceField的情況下)或多個模型對象(在ModelMultipleChoiceField的情況下)放置到cleaned_data表單的字典。
class ModelChoiceField(**kwargs)
- 默認的Widget:Select
- 空值:None
- 規范化為:一個模型實例。
- 驗證給定的id存在於查詢集中。
- 錯誤信息的鍵:required, invalid_choice
class ModelMultipleChoiceField(**kwargs)
- 默認的Widget:SelectMultiple
- 空值:QuerySet (self.queryset.none())
- 規范化為: 模型實例的一個QuerySet。
- 驗證在給定的值列表中的每個id存在於查詢集中。
- 錯誤信息的鍵:required, list, invalid_choice, invalid_pk_value
- 創建自定義的字段
如果內建的字段不能滿足你的需求,你可以很容易地創建自定義的字段。你需要創建django.forms.Field 的一個子類。它只要求實現一個clean() 方法和接收上面核心參數的init() 方法(required, label, initial, widget, help_text)。
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類型 ...
1.1 字段命名約束
字段是模型中最重要的內容之一,也是唯一必須的部分。字段在Python中表現為一個類屬性,體現了數據表中的一個列,請不要使用 clean , save , delete 等Django內置的模型API名字,防止命名沖突。下面是一個展示,注意字段的寫法:
from django.db import models class Musician(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) instrument = models.CharField(max_length=100) class Album(models.Model): artist = models.ForeignKey(Musician, on_delete=models.CASCADE) name = models.CharField(max_length=100) release_date = models.DateField() num_stars = models.IntegerField()
Django不允許下面兩種字段名:
- 與Python關鍵字沖突。這會導致語法錯誤,例如:
class Example(models.Model): pass = models.IntegerField() # 'pass'是Python保留字!
- 字段名中不能有兩個以上下划線在一起,因為兩個下划線是Django的查詢語法,例如:
class Example(models.Model): foo__bar = models.IntegerField() # 'foo__bar' 有兩個下划線在一起!
由於你可以自定義表名,列名,上面的規則可能被繞開,但是請養成良好的習慣,一定不要那么起名。
SQL語言的join,where和Select 等保留字可以作為字段名,因為Django對他們都進行了轉義。
二,django模型字段常用參數
2.1,null
如果是True,Django會在數據庫中將次字段的值置為NULL,默認值為False。(null=True是允許數據庫這個值是空)
2.2,blank
如果為True時,django的Admin添加數據時可允許空值,可以不填。如果為False,則必須填。默認為False。(black=True 表示允許表單驗證為空)
2.3,primary_key = False
主鍵,對AutoFiled設置主鍵后,就會代替原來的自增ID列
2.4,auto_now 和 auto_now_add
auto_now 自動創建——無論添加或者修改,都是當前操作的時間
auto_now_add 自動創建——永遠是創建時的時間
2.5,choices
一個二維的元組被用作choices,如果這樣定義,Django會select box代替普通的文本框,並且限制choices的值時元組中的值。
2.6,max_length
字段長度
2.7,default
默認值
2.8,verbose_name
Admin中字段的顯示名稱,如果不設置該參數時,則與屬性名
2.9,db_column
數據庫中的字段名稱
2.10,unique = True
不允許重復
2.11,db_index = True
數據庫索引
2.12,editable = True
在Admin里是否可以編輯
2.13,error_messages = None
錯誤提示
2.14,auto_created = Flase
自動創建
三,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
四,常用選擇插件——widget
widget是form表單最重要的參數之一,指定渲染Widget時使用的widget類,舉個例子:就是說這個form字段在HTML頁面中為文本輸入框,密碼輸入框,單選框,多選框。。。。。
4.1,密碼輸入框
pwd = forms.CharField( min_length=6, label="密碼", widget=forms.widgets.PasswordInput()
4.2,單radioSelect
單radio值為字符串
user_type_choice = ( (0, u'普通用戶'), (2, u'高級用戶'), ) user_type = forms.IntegerField(initial=2, widget=forms.widgets.RadioSelect(choices=user_type_choice,))
4.3,單選select
user_type_choice = ( (0, u'普通用戶'), (2, u'高級用戶'), ) user_type = forms.IntegerField(initial=2, widget=forms.widgets.Select(choices=user_type_choice,))
4.4,多選select
user_type_choice = ( (0, u'普通用戶'), (2, u'高級用戶'), ) user_type = forms.IntegerField(initial=[1, ], widget=forms.widgets.SelectMultiple(choices=user_type_choice,))
4.5,單選checkbox
user_type = forms.CharField(widget=forms.widgets.CheckboxInput())
4.6,多選checkbox
值為列表
user_type_choice = ( (0, u'普通用戶'), (2, u'高級用戶'), ) user_type = forms.CharField( initial=[2, ], widget=forms.widgets.CheckboxSelectMultiple( choices=user_type_choice, ))
4.7 關於choice的注意事項
在使用選擇標簽的時候,需要注意choices的選項可以從數據庫獲取,但是由於是靜態子彈,獲取的值無法更新,那么需要自定義構造方法從而達到目的。
5,如何上傳文件和圖片的方法
5.1,FileField
class FileField(upload_to=None, max_length=100, **options)[source]
上傳文件字段(不能設置為主鍵)。默認情況下,該字段在HTML中表現為一個ClearableFileInput 標簽。在數據庫內,我們實際保存的是一個字符串類型,默認最大長度為100,可以通過max_length 參數自定義。真實的文件是保存在服務器的文件系統內的。
重要參數upload_to 用於設置上傳地址的目錄和文件名。如下例所示:
class MyModel(models.Model): # 文件被傳至`MEDIA_ROOT/uploads`目錄,MEDIA_ROOT由你在settings文件中設置 upload = models.FileField(upload_to='uploads/') # 或者 # 被傳到`MEDIA_ROOT/uploads/2015/01/30`目錄,增加了一個時間划分 upload = models.FileField(upload_to='uploads/%Y/%m/%d/')
Django很人性化的幫我們實現了根據日期生成目錄的方式!
upload_to 參數也可以接收一個回調函數,該函數返回具體的路徑字符串,如下例:
def user_directory_path(instance, filename): #文件上傳到MEDIA_ROOT/user_<id>/<filename>目錄中 return 'user_{0}/{1}'.format(instance.user.id, filename) class MyModel(models.Model): upload = models.FileField(upload_to=user_directory_path)
例子中,user_directory_path 這種回調函數,必須接收兩個參數,然后返回一個Unix風格的路徑字符串。參數instace代表一個定義了FileField的模型的實例,說白了就是當前數據記錄。filename是原本的文件名。
5.2,ImageField
class ImageField(upload_to=None, height_field=None, width_field=None, max_length=100, **options)[source]
用於保存圖像文件袋額字段。其基本用法和特征與FileField一樣,只不過多了兩個屬性height和width。默認清洗下,該字段在HTML中表現為一個ClearableFileInput 標簽。在數據庫內,我們實際保存的是一個字符串類型。默認最大長度100,可以通過max_length 參數自定義。真實的圖片是保存在服務器的文件系統內的。
- height_field參數:保存有圖片高度信息的模型字段名
- width_field參數:保存有圖片寬度信息的模型字段名
使用Django的ImageField需要提前安裝pillow模塊。
使用FileField或者ImageField字段的步驟:
- 1,在settings文件中宏,配置MEDIA_ROOT,作為你上傳文件在服務器中的基本路徑(為了性能考慮,這些文件不會被存儲在數據庫中)。再配置個MEDIA_URL ,作為公用URL,指向上傳文件的基本路徑。請確保Web服務器的用戶賬號對該目錄具有寫的權限。
- 2,添加FileField或者ImageField字段到你的模型中,定義好upload_to參數,文件最終會放在MEDIA_ROOT目錄的“upload_to”子目錄中。
- 3,所有真正被保存在數據庫中的,只是指向你上傳文件路徑的字符串而已。可以通過url屬性,在Django的模板中方便的訪問這些文件。例如,假設你有一個ImageField字段,名為mug_shot,那么在Django模塊的HTML文件中,可以使用{{ object.mug_shot.url }} 來獲取該文件。其中的object 用你具體的對象名稱代替。
- 4,可以通過name 和 size 屬性,獲取文件的名稱和大小信息。
安全建議
無論你如何保存上傳的文件,一定要注意他們的內容和格式,避免安全漏洞!務必對所有上傳文件進行安全檢查,確保他們不出問題! 如果你不加任何檢查就盲目的讓任何人上傳到你的服務器文檔根目錄內,比如上傳了一個CGI 或者PHP腳本,很可能就會被訪問的用戶執行,這具有致命的危害。
5.3,FilePathField
class FilePathField(path=None, match=None, recursive=False, max_length=100, **options)[source]
一種用來保存文件路徑信息的子段。在數據表內以字符串的形式存在,默認最大長度100,可以通過max_length參數設置。
他們包含有下面的一些參數:
- path:必須指定的參數。表示一個系統絕對路徑
- match:可選參數,一個正則表達式,用於過濾文件名。只匹配基本文件名,不匹配路徑。例如foo.*\.txt$ ,只匹配文件名 foo23.txt,不匹配bar.txt 與 foo23.png 。
- recursive:可選參數,只能是True或者FALSE。默認為FALSE。決定是否包含子目錄,也就是是否遞歸的意思。
- allow_files:可選參數,只能是True或者False。默認為True,決定是否應該將文件名包括在內。它和allow_folders其中,必須有一個為True。
- allow_folders:可選參數,只能是True或者Flase。默認為False,決定是否應該將目錄名包括在內。
比如:
FilePathField(path="/home/images", match="foo.*", recursive=True)
他只匹配/home/images/foo.png ,但是不匹配 /home/images/foo/bar.png ,因為默認情況,只匹配文件名,而不管路徑怎么樣的。
5.4,UUIDField
數據庫無法為自己生成uuid,因此需要如下使用default參數:
import uuid # Python的內置模塊 from django.db import models class MyUUIDModel(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) # 其它字段
5.5,上傳文件實例
views.py
from django.shortcuts import render, HttpResponse import os def upload(request): if request.method == 'GET': # return HttpResponse("OK") return render(request, 'user8_book/upload.html') elif request.method == 'POST': # print("OK") # return HttpResponse("OK") obj = request.FILES.get('file') print(obj.name) f = open(os.path.join('static/upload', obj.name), 'wb') for line in obj.chunks(): f.write(line) f.close() return HttpResponse('上傳成功')
urls.py
from django.conf.urls import url, include from django.contrib import admin from user8_book import views from django.urls import path urlpatterns = [ path('book/', views.book), path('upload.html/', views.upload), ]
models.py
from django.db import models # Create your models here. class Upload(models.Model): text = models.CharField(max_length=100) file = models.FileField(max_length=128)
upload.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>upload</title> </head> <body> {# 文件上傳的form#} {#<form method="post" enctype="multipart/form-data">#} <form method="post" action="/user8_book/upload.html/" enctype="multipart/form-data"> {% csrf_token %} <p><input id="name" type="text" name="input-name" placeholder="請輸入文件名稱" ></p> <p><input id="file" type="file" name="file"></p> <p><input id="submit" type="submit" value="submit"></p> </form> </body> </html>
5.6,上傳文件報錯及其解決方法
報錯內容:
解決方法:
查看自己的HTML文件中,表單的action屬性值結尾是否添加了“/”,我就是因為沒有添加,找了半天錯誤,真尷尬。粗心大意
Django:Form表單(驗證,定制錯誤信息,Select)
1,Django from流程
- 1,創建類,繼承form.Form
- 2,頁面根據類的對象自動創建HTML標簽
- 3,提交,request.POST 封裝到類的對象里,obj=UserInfo(request.POST)
- 4,用戶輸入是否合法 obj.is_valid()
- 5,全部合法,獲取全部內容 obj.claen()
- 6,只有有不合法 obj.errors
2,Form表單使用建議
我們可以在APP目錄下新建立一個myforms.py文件,然后再建立form。為什么要新建一個myforms.py呢?其好處顯而易見:
- 所有的表單在一個文件里,非常便於后期維護,比如增添或者修訂字段。
- myform.py可以通過clean方法自定義表單驗證,非常便捷,不用在views.py里再進行表單驗證(比如檢查用戶是否已經存在等等),邏輯更加清晰
3,定制表單
一般情況下,使用一種東西就會受制於一種東西,但是這並不是Django的意願。並非你接受了django表單的方便就需要接受這么丑陋的頁面。Django表單時可以隨你心願定制的。
我們不但可以對標簽名進行定制化,還可以限制輸入的位數,比如下面代碼,我們限制了輸入九位,第十位就無法輸入,而且並非所有的信息都是強制填的,可以根據需要來抉擇,同樣看下面代碼,即使email空着不填,表單也能正常提交。
class UserInfo(forms.Form): email = forms.EmailField(required=False) host = forms.CharField(max_length=9) port = forms.CharField(max_length=4) mobile = forms.CharField(max_length=11)
4,美化表單
每個表單字段都有一個對應的Widget class,它對應一個HTML表單Widget,我們可以使用Forms中的widget來對我們的前端表按照我們的要求進行改造
4.1 示例1:長文本輸入框
比如當我們需要做一個長文本輸入框時候:
class UserInfo(forms.Form): email = forms.EmailField(required=False) host = forms.CharField(max_length=9) port = forms.CharField(max_length=4) mobile = forms.CharField(max_length=11) comment = forms.CharField(widget=forms.Textarea)
html代碼如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/user15_form/user_list/" method="post"> {% csrf_token %} <p>主機:{{ obj.host }}<span>{{ errors.host }}</span></p> <p>端口:{{ obj.port }}<span>{{ errors.port }}</span></p> <p>郵箱:{{ obj.email }}<span>{{ errors.email }}</span></p> <p>手機:{{ obj.mobile }}<span>{{ errors.mobile }}</span></p> <p>評論:{{ obj.comment }}<span>{{ errors.comment }}</span></p> <input type="submit" value="提交"> </form> </body> </html>
效果如下:
4.2 示例二:下拉框
當我們想做一個下拉框的時候:
其views.py代碼如下:
from django.shortcuts import render # Create your views here. from django import forms from django.forms.widgets import SelectDateWidget class UserInfo(forms.Form): email = forms.EmailField(required=False) host = forms.CharField(max_length=9) port = forms.CharField(max_length=4) mobile = forms.CharField(max_length=11) comment = forms.CharField(widget=forms.Textarea) years = ('2010', '2019', '2029') year = forms.DateField(widget=SelectDateWidget(years=years)) def user_list(request): obj = UserInfo() if request.method == 'POST': user_input_obj = UserInfo(request.POST) if user_input_obj.is_valid(): # 如果輸入合法的話,就獲取輸入的值 data = user_input_obj.clean() print(data) else: # 獲取錯誤信息 error_msg = user_input_obj.errors return render(request, 'user15_form/user_list.html', {'obj':user_input_obj, 'errors':error_msg}) return render(request, 'user15_form/user_list.html', {'obj':obj})
HTML代碼如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/user15_form/user_list/" method="post"> {% csrf_token %} <p>主機:{{ obj.host }}<span>{{ errors.host }}</span></p> <p>端口:{{ obj.port }}<span>{{ errors.port }}</span></p> <p>郵箱:{{ obj.email }}<span>{{ errors.email }}</span></p> <p>手機:{{ obj.mobile }}<span>{{ errors.mobile }}</span></p> <p>評論:{{ obj.comment }}<span>{{ errors.comment }}</span></p> <p>年份:{{ obj.year }}<span>{{ errors.year }}</span></p> <input type="submit" value="提交"> </form> </body> </html>
結果展示如下:
4.3 示例三:自己定制輸入框
對ChoiceField字段,Form默認的是集成select的widget,即使用HTML的列表形式<select>,而RadioSelect使用單選按鈕。 如果想要某一個輸入框看起來更特別,不一樣的話,你可以這樣做:
views.py 的代碼如下(這里只修改了comment的代碼):
comment = forms.CharField(widget=forms.TextInput(attrs={'size':'40'}))
我們為其設置了attrs,也就是HTML中的css屬性。(要是想為整個表單或者更深度的定制一些css以及JavaScript,可以前往Django官方文檔了解)
效果如下:
5,Form表單字段
5.1 Field.clean(value)
雖然字段類主要使用在表單類中,但是我們也可以直接實例化他們來使用,以便更好地了解他們是如何工作的。每個字段實例都有一個clean()方法,它接受一個參數,然后返回“清潔的”數據或者拋出一個django.forms.
>>> from django import forms >>> f = forms.EmailField() >>> f.clean('foo@example.com') 'foo@example.com' >>> f.clean('invalid email address') Traceback (most recent call last): ... ValidationError: ['Enter a valid email address.']
每個字段類的構造函數至少接受這些參數。有些字段類接受額外的,字段特有的參數,但以下參數應該總能接受:
5.2 Field.required
默認情況下,每個字段都假設必須有值,所以如果你傳遞一個空的值——不管是None,還是空字符串(" ")——clean() 都將引發一個ValidationError異常。
>>> from django import forms >>> f = forms.CharField() >>> f.clean() Traceback (most recent call last): File "<input>", line 1, in <module> TypeError: clean() missing 1 required positional argument: 'value' >>> f.clean("") Traceback (most recent call last): File "<input>", line 1, in <module> File "C:\Users\Administrator\AppData\Local\Programs\Python\Python37\lib\site-packages\django\forms\fields.py", line 148, in clean self.validate(value) File "C:\Users\Administrator\AppData\Local\Programs\Python\Python37\lib\site-packages\django\forms\fields.py", line 126, in validate raise ValidationError(self.error_messages['required'], code='required') django.core.exceptions.ValidationError: ['This field is required.'] >>> f.clean("12") '12'
5.3 Field.label
正如前面“輸出表單為HTML”中解釋的,字段默認label是通過將字段名中所有的下划線轉換成空格並大寫第一個字母生成的。如果默認的標簽不合適,可以指定label。
>>> from django import forms >>> class CommentForm(forms.Form): ... name = forms.CharField(label='Your name') ... url = forms.URLField(label='Your Web site', required=False) ... comment = forms.CharField() >>> f = CommentForm(auto_id=False) >>> print(f) <tr><th>Your name:</th><td><input type="text" name="name" /></td></tr> <tr><th>Your Web site:</th><td><input type="url" name="url" /></td></tr> <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
5.4 Field.label_suffix
label_suffix參數讓你基於每個字段覆蓋表單的label_suffix
>>> class ContactForm(forms.Form): ... age = forms.IntegerField() ... nationality = forms.CharField() ... captcha_answer = forms.IntegerField(label='2 + 2', label_suffix=' =') >>> f = ContactForm(label_suffix='?') >>> print(f.as_p()) <p><label for="id_age">Age?</label> <input id="id_age" name="age" type="number" /></p> <p><label for="id_nationality">Nationality?</label> <input id="id_nationality" name="nationality" type="text" /></p> <p><label for="id_captcha_answer">2 + 2 =</label> <input id="id_captcha_answer" name="captcha_answer" type="number" /></p>
5.5 Field.initial
initial 參數讓你指定渲染未綁定的表單中的字段時使用的初始值。
5.6 Field.widget
widget參數讓你指定渲染表單時使用的Widget類,更多信息參見上面。
5.7 Filed.help_text
5.8 Field.error_messages
error_messages 參數讓你覆蓋字段引發的異常中的默認信息。傳遞的是一個字典,其鍵為你想覆蓋的錯誤信息。
5.9 Field.validators
validators 參數讓你可以為字段提供一個驗證函數的列表。
5.10 Field.localize
localize 參數啟用表單數據的本地化,包括輸入和輸出。
5.11 Field.has_changed()
has_changed() 方法用於決定字段的值是否從初始值發送了變化。返回True或者False。
6,form關於clean及其cleaned_data的說明
django表單驗證中比較有用的就是clean和cleaned_data了。
clean是在is_valid()內部調用的,cleaned_data主要用來檢查字段是否符合定義的格式,讀取表單返回的值,如果是則返回類型為字段dict型。
比如email = cleaned_data['email'] 讀取name為“email”的表單提交值,並賦予email變量。
cleaned_data中的值類型與字段定義的Field類型一致。如果字段定義charfield,那么clean方法返回的cleaned_data中對應的字段值就是字符型,定義為ModelChoiceField,那么cleaned_data中字段值是某個model實例。定義為ModelMultipleChoiceField,則cleaned_data中字段值是model實例list。
Django:表單實例
首先我們看一下下面的案例:
#/usr/bin/env python #-*- coding:utf-8 -*- from django.shortcuts import render # Create your views here. def user_list(request): host = request.POST.get('host') port = request.POST.get('port') mail = request.POST.get('mail') mobile = request.POST.get('mobile') #這里有個問題,如果,這個from表單有20個input,你在這里是不是的取20次? #驗證: #輸入不能為空,並且有的可以為空有的不可以為空 #如果email = 11123123 這樣合法嗎? #如果mobile = 11123123 這樣合法嗎? #如果ip = 11123123 這樣合法嗎? ''' 你在這里是不是需要做一大堆的輸入驗證啊?並且有很多這種頁面會存在這種情況,如果每個函數都這樣做估計就累死了 ''' return render(request,'user_list.html')
針對於上面的問題,如何解決呢?——那就是Form表單
Django中form表單的作用:
- 1,自動生成HTML表單元素
- 2,用來做用戶提交的驗證
- 3,檢查表單數據的合法性
- 4,回顯功能(驗證錯誤,輸入數據不會被清空)
- 5,數據類型轉換(轉換成相應的python類型)
通常提交表單數據就是由HTML表單向后台傳遞信息,后台通過request.GET() 或者 request.POST()獲取。
一,構建一個簡單表單的流程,並提交信息給數據庫
1.1,建立一個django項目
建一個Blog項目,並在template下新建兩個html頁面,一個注冊頁面命名為register,一個歡迎頁面為welcome。
1,創建project django-admin startproject Blog 2,創建APP python manage.py startapp user1 3,修改settings配置 在INSTALLED_APPS中添加APP:user1 在TEMPLATES中查看“DIRS”內容,如果有template,請保持原樣,如果沒有,則添加 'DIRS': [os.path.join(BASE_DIR, 'templates')]
項目目錄如下:
1.2, 填充HTML文件內容
給template下兩個html頁面register和welcome填充內容。
register.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>register</title> </head> <body> <form action="/user/register/" method="post"> {% csrf_token %} <p>用戶名:<input type="text" name="username"></p> <p>密碼: <input type="password" name="password"></p> <input type="submit" value="submit"> </form> </body> </html>
welcome.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>welcome</title> </head> <body> <h1>welcome to this page</h1> </body> </html>
1.3,在models中創建表結構
在user1/models.py中創建表結構,代碼如下:
from django.db import models # Create your models here. class BlogUser(models.Model): username = models.CharField(max_length=200, unique=True) password = models.CharField(max_length=200)
ChariField 字符串字段,用於較短的字符串,需要max_length來指定VARCHAR數據庫字段的大小。
同時,修改Bolg/settings.py的內容:
找到下面這段代碼,並注釋掉: DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } } 然后寫入下面代碼: import pymysql pymysql.install_as_MySQLdb() DATABASES = { 'default': { # 這里可以指定使用的數據庫類型,例如mysql 'ENGINE': 'django.db.backends.mysql', 'NAME': 'blog_demo', 'USER':'root', 'PASSWORD':'******', 'HOST':'localhost', 'PORT':'3306', } }
如果這里不熟悉請參考:Django連接MySQL數據庫
並且,映射數據庫,這一步不能忘記:
在終端創建表 1,生成同步數據庫的代碼: python manage.py makemigrations 2,同步數據庫(也就是對數據庫執行真正的遷移動作): python manage.py migrate
1.4,以創建對象的方式操作數據庫
我們重構views.py中的代碼
from django.shortcuts import render # Create your views here. from user1.models import BlogUser def register(request): if request.method =='GET': return render(request, 'register.html') elif request.method == 'POST': bloguser = BlogUser() bloguser.username = request.POST.get('username') bloguser.password = request.POST.get('password') bloguser.save() return render(request, 'welcome.html')
get() 中的username和password是取的register 里的username的值。以獲取(request)注冊的信息,保存為save()。
然后運行項目,並注冊信息,代碼如下:
1, 運行項目 python manage.py runserver 2,在瀏覽器中輸入: http://127.0.0.1:8000/user/register/
然后我們注冊信息,並提交。我們可以看到上面的register.html中用戶名是唯一的,所以當我們注冊相同的名稱時候回報錯500,並且傳輸失敗。
下面在數據庫看一下我們的注冊信息
其中,3,5不顯示,因為我輸入了相同的用戶名。如果輸入不重復,則顯示下面界面。
二,構建一個簡單表單的流程,了解Form知識
在上面的基礎上,我們再實現一個表單流程,繼續了解form表單的知識。
2.1,首先創建對應的視圖函數 views.py內容如下:
from django.shortcuts import render, HttpResponse # Create your views here. from django import forms class LoginForm(forms.Form): account = forms.CharField() password = forms.CharField() email = forms.CharField() def login(request): if request.method == "POST": form = LoginForm(request.POST) if form.is_valid(): return HttpResponse("登錄成功") else: form = LoginForm() return render(request, 'user6/login.html',{'form':form})
2.2,建立對應的模板 login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div align="center" style="height: 400px; width: 100px;"> <form action="#" method="post"> {% csrf_token %} {{ form }} <button type="submit" id="sum">submit</button> </form> </div> </body> </html>
然后,去配置urls一些基本的配置(比如模板,路由等)。
我們直接點開login.html 內容如下:
我們打開Django項目,從127.0.0.1:8000/user6/login/ 進入,如下:
直接訪問地址就顯示出這樣一個簡單的界面,由HTML文件可以看到並沒有js代碼對數據有效性進行驗證,我們隨機輸入賬號,密碼,郵箱,則提交,顯示登陸成功。如下:
三,定制表單
從上面的代碼我們發現,前端一個 {{ form }} 就能做出一個完整強大的表單。但是我們只能用account password 做名稱嗎?
不是的,這里我們可以定制其名字,並且可以限制輸入位數等等各種操作。
3.1,如何給form表單設置自定義報錯內容
在form里有一個參數:error_messages 在他這里就可以定義報錯內容
class UserInfo(forms.Form): # required是否可以為空,如果為False,則說明可以為空 email = forms.EmailField(required=False,error_messages={'required':u'郵箱不能為空'}) # 如果required 不寫默認為Ture host = forms.CharField(error_messages={'required':u'主機不能為空'}) port = forms.CharField(error_messages={'required':u'端口不能為空'}) mobile = forms.CharField(error_messages={'required':u'手機不能為空'})
3.2,如何給form表單添加一個屬性
class UserInfo(forms.Form): # required是否可以為空,如果為False,則說明可以為空 email = forms.EmailField(required=False,error_messages={'required':u'郵箱不能為空'}) # 如果required 不寫默認為Ture host = forms.CharField(error_messages={'required':u'主機不能為空'}) port = forms.CharField(error_messages={'required':u'端口不能為空'}) mobile = forms.CharField(error_messages={'required':u'手機不能為空'}, # 這里默認是TextInput 標簽 widget = forms.TextInput(attrs={'class':'form-control', 'placeholder':u'手機號碼'}))
3.3,如何給form表單添加一個備注
class UserInfo(forms.Form): # required是否可以為空,如果為False,則說明可以為空 email = forms.EmailField(required=False,error_messages={'required':u'郵箱不能為空'}) # 如果required 不寫默認為Ture host = forms.CharField(error_messages={'required':u'主機不能為空'}) port = forms.CharField(error_messages={'required':u'端口不能為空'}) mobile = forms.CharField(error_messages={'required':u'手機不能為空'}, # 這里默認是TextInput 標簽 widget = forms.TextInput(attrs={'class':'form-control', 'placeholder':u'手機號碼'})) # 我們再這里新增一個備份 memo = forms.CharField(required=False, widget=forms.Textarea(attrs={'class':'form-control','placeholder':u'備份'}))
同樣的HTML代碼也要新增:
<form action="/user_list/" method="post"> <p>主機 : {{ obj.host }}<span>{{ errors.host }}</span></p> <p>端口 : {{ obj.port }}<span>{{ errors.port }}</span></p> <p>郵箱 : {{ obj.email }}<span>{{ errors.email }}</span></p> <p>手機 : {{ obj.mobile }}<span>{{ errors.mobile }}</span></p> <p>備注:{{ obj.memo }}<span>{{ errors.memo }}</span></p> <input type="submit" value="submit"> </form>
3.4,自定義正則表達式增加判斷規則
import re from django import forms from django.core.exceptions import ValidationError def mobile_validate(value): # 正則匹配 mobile_re = re.compile(r'^(13[0-9]|15[0123456789]|18[0-9]|14[57])[0-9]{8}$') if not mobile_re.match(value): raise ValidationError("手機號碼格式錯誤") class UserInfo(forms.Form): # required是否可以為空,如果為False,則說明可以為空 email = forms.EmailField(required=False, error_messages={'required': u'郵箱不能為空'}) host = forms.CharField(error_messages={'required': u'主機不能為空'}) port = forms.CharField(error_messages={'required': u'端口不能為空'}) mobile = forms.CharField(# 應用我們自己定義的規則 validators=[mobile_validate,], error_messages={'required': u'手機不能為空'}, # 這里默認使用TextInput 標簽 widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': u'手機號碼'})) # 我們新增一個備份 memo = forms.CharField(required=False, widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': u'備份'})) def user_list(request): # 創建了這個對象 obj = UserInfo() if request.method == 'POST': # 獲取用戶輸入一句話就搞定 user_input_obj = UserInfo(request.POST) # 判斷用戶輸入是否合法 if user_input_obj.is_valid(): # 獲取用戶輸入 data = user_input_obj.clean() print(data) else: # 如果發生錯誤,捕獲異常 # 這里原來什么都沒寫,默認是ul的樣式,默認是as_ul(), # 如果我們寫成as_data()返回的就是一個原生的字符串 # 還有一個as_json error_msg = user_input_obj.errors.as_data() # 然后把錯誤信息返回 print(error_msg) # 然后把對象傳給html,在把錯誤信息傳遞過去 return render(request, 'user6/register.html', {'obj': obj, 'errors': error_msg,}) # 將對象傳給html return render(request, 'user6/register.html', {'obj':obj,})
當我們輸入不合法的時候,或者不是email格式的時候,會出現如下錯誤:
這樣后端我們就有一套驗證的機制了,就是通過is_valid()來判斷用戶輸入是否合法!如果不合法就把返回的信息發送出去,如果合法獲取數據,繼續操作即可!
3.5,生成select標簽
class UserInfo(forms.Form): user_type_choice = ( (0,u'普通用戶'), (1,u'高級用戶'), ) user_type = forms.IntegerField(widget=forms.widgets.Select(choices=user_type_choice, attrs={'class':'form-control'})) # required是否可以為空,如果為False,則說明可以為空 email = forms.EmailField(required=False,error_messages={'required':u'郵箱不能為空'}) # 如果required 不寫默認為Ture host = forms.CharField(error_messages={'required':u'主機不能為空'}) port = forms.CharField(error_messages={'required':u'端口不能為空'}) mobile = forms.CharField(error_messages={'required':u'手機不能為空'}, # 這里默認是TextInput 標簽 widget = forms.TextInput(attrs={'class':'form-control', 'placeholder':u'手機號碼'})) # 我們再這里新增一個備份 memo = forms.CharField(required=False, widget=forms.Textarea(attrs={'class':'form-control','placeholder':u'備份'}))
HTML內更改如下:
<form action="/user_list/" method="post"> <p>用戶類型:{{ obj.user_type }}<span>{{ errors.user_type }}</span></p> <p>主機 : {{ obj.host }}<span>{{ errors.host }}</span></p> <p>端口 : {{ obj.port }}<span>{{ errors.port }}</span></p> <p>郵箱 : {{ obj.email }}<span>{{ errors.email }}</span></p> <p>手機 : {{ obj.mobile }}<span>{{ errors.mobile }}</span></p> <p>備注:{{ obj.memo }}<span>{{ errors.memo }}</span></p> <input type="submit" value="submit"> </form>
3.6.關於后端驗證
這個后端驗證是必須要有驗證機制的,前端可以不寫但是后端必須寫,前端的JS是可以被禁用掉的,在實際的生產環境中比如登錄和驗證的時候,我們一般都使用 JQuery+AJAX 來判斷用戶的輸入是否為空,假如JS被禁用(瀏覽器端可以設置禁用JS效果)的話,我們這個認證屏障是不是就消失了呢?(雖然一般不會禁用但是還是存在風險),所以我們一般做兩種認證,在前端做一遍認證,在后端做一遍認證。
3.7,代碼總結
import re from django import forms from django.core.exceptions import ValidationError #自定義方法 def mobile_validate(value): mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$') #正則匹配 if not mobile_re.match(value): raise ValidationError('手機號碼格式錯誤') #如果沒有匹配到主動出發一個錯誤 class UserInfo(forms.Form): user_type_choice = ( (0, u'普通用戶'), (1, u'高級用戶'),) user_type = forms.IntegerField(widget=forms.widgets.Select(choices=user_type_choice,attrs={'class':'form-control'})) email = forms.EmailField(required=True,error_messages={'required':u'郵箱不能為空'}) #required是否可以為空,如果為False說明可以為空 host = forms.CharField(error_messages={'required':u'主機不能為空'}) #如果required不寫默認為Ture port = forms.CharField(error_messages={'required':u'端口不能為空'}) #默認mobile里有一個默認為空的機制,我們在原有的參數里增加怎們自定義的方法 mobile = forms.CharField(validators=[mobile_validate,],#應用咱們自己定義的規則 error_messages={'required':u'手機不能為空'}, widget=forms.TextInput(attrs={'class':'form-control','placeholder':u'手機號碼'}) #這里默認是TextInput,標簽 ) #咱們在新增一個備注 memo = forms.CharField(required=False, widget=forms.Textarea(attrs={'class':'form-control','placeholder':u'備注'})) def user_list(request): obj = UserInfo() #創建了這個對象 if request.method == 'POST': #獲取用戶輸入一句話就搞定 user_input_obj = UserInfo(request.POST) if user_input_obj.is_valid(): #判斷用戶輸入是否合法 data = user_input_obj.clean() #獲取用戶輸入 print data else: #如果發生錯誤,捕捉錯誤 error_msg = user_input_obj.errors.as_data()#這里原來什么都沒寫,默認是ul的樣式,默認是as_ul(),如果我們寫成as_data()返回的就是一個原生的字符串 #還有一個as_json print error_msg #打印一下然后看下他的類型 #然后把錯誤信息返回 return render(request,'user_list.html',{'obj':obj,'errors':error_msg,})#然后把對象傳給html,在把錯誤信息傳遞過去 return render(request,'user_list.html',{'obj':obj,})#然后把對象傳給html
參考文獻:https://blog.csdn.net/qq_42068900/article/details/80904596
https://blog.csdn.net/qq_37049781/article/details/79283547