Django之Form組件
Django之Form組件
本節內容
- 基本使用
- form中字段和插件
- 自定義驗證規則
- 動態加載數據到form中
1. 基本使用
django中的Form組件有以下幾個功能:
- 生成HTML標簽
- 驗證用戶數據(顯示錯誤信息)
- HTML Form提交保留上次提交數據
- 初始化頁面顯示內容
要使用form類,首先需要創建這個類,方法如下:
from django.forms import Form from django.forms import widgets # 插件 from django.forms import fields # 字段 class MyForm(Form): # 繼承自Form類 user = fields.CharField( widget=widgets.TextInput(attrs={'id': 'i1', 'class': 'c1'}) # 定義生成的html標簽類型是input的text框,attrs={'id': 'i1', 'class': 'c1'}代表在這個標簽中添加屬性ID為i1,添加class為c1 ) gender = fields.ChoiceField( choices=((1, '男'), (2, '女'),), # 定義下拉框的選項,元祖第一個值為option的value值,后面為html里面的值 initial=2, # 默認選中第二個option widget=widgets.RadioSelect # 插件表現形式為單選按鈕 ) city = fields.CharField( initial=2, # 初始值為2 widget=widgets.Select(choices=((1,'上海'),(2,'北京'),)) # 插件表現形式為下拉框 ) pwd = fields.CharField( widget=widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True) # 插件表現形式為密碼輸入框 )
之后在views視圖中定義:
from django.shortcuts import render, redirect from .forms import MyForm def index(request): if request.method == "GET": obj = MyForm() # 沒有值,在頁面上渲染form中的標簽 return render(request, 'index.html', {'form': obj}) elif request.method == "POST": obj = MyForm(request.POST, request.FILES) # 將post提交過來的數據作為參數傳遞給自定義的Form類 if obj.is_valid(): # obj.is_valid()返回一個bool值,如果檢查通過返回True,否則返回False values = obj.clean() # 拿到處理后的所有數據,鍵值對的形式 print(values) else: errors = obj.errors # 拿到未通過的錯誤信息,里面封裝的都是對象 print(errors) return render(request, 'index.html', {'form': obj}) else: return redirect('http://www.google.com')
模板定義:
<form action="/" method="POST" enctype="multipart/form-data">
<p>{{ form.user }} {{ form.errors.user.0 }}</p> <!--{{ form.user }}生成標簽,{{ form.user.errors }}生成第一個錯誤信息-->
<p>{{ form.gender }} {{ form.errors.gender.0 }}</p>
<p>{{ form.city }} {{ form.errors.city.0 }}</p>
<p>{{ form.pwd }} {{ form.errors.pwd.0 }}</p>
<input type="submit"/>
</form>
其他相關標簽
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form.xxoo.label }}
{{ form.xxoo.id_for_label }}
{{ form.xxoo.label_tag }}
{{ form.xxoo.errors }}
<p>{{ form.user }} {{ form.user.errors }}</p>
<input type="submit" />
</form>
2. form中字段和插件
創建Form類時,主要涉及到 【字段】 和 【插件】,字段用於對用戶請求數據的驗證,插件用於自動生成HTML;
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='', 幫助提示 TypedChoiceField(ChoiceField) coerce = lambda val: val 對選中的值進行一次轉換,通過lambda函數實現 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類型 ...
注:UUID是根據MAC以及當前時間等創建的不重復的隨機字符串
>>> import uuid # make a UUID based on the host ID and current time >>> uuid.uuid1() # doctest: +SKIP UUID('a8098c1a-f86e-11da-bd1a-00112444be1e') # make a UUID using an MD5 hash of a namespace UUID and a name >>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org') UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e') # make a random UUID >>> uuid.uuid4() # doctest: +SKIP UUID('16fd2706-8baf-433b-82eb-8c7fada847da') # make a UUID using a SHA-1 hash of a namespace UUID and a name >>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org') UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d') # make a UUID from a string of hex digits (braces and hyphens ignored) >>> x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}') # convert a UUID to a string of hex digits in standard form >>> str(x) '00010203-0405-0607-0809-0a0b0c0d0e0f' # get the raw 16 bytes of the UUID >>> x.bytes b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f' # make a UUID from a 16-byte string >>> uuid.UUID(bytes=x.bytes) UUID('00010203-0405-0607-0809-0a0b0c0d0e0f')
2.Django內置插件:
TextInput(Input) #input type="text" NumberInput(TextInput) # 數字輸入框 EmailInput(TextInput) # 郵箱輸入框 URLInput(TextInput) # url輸入框 PasswordInput(TextInput) # 密碼輸入框 HiddenInput(TextInput) # 隱藏輸入框 Textarea(Widget) # textarea文本區 DateInput(DateTimeBaseInput) # 日期輸入框 DateTimeInput(DateTimeBaseInput) # 日期時間輸入框 TimeInput(DateTimeBaseInput) # 時間輸入框 CheckboxInput # 多選框 Select # 下拉框 NullBooleanSelect # 非空布爾值下拉框 SelectMultiple # 多選下拉框 RadioSelect # 單選框 CheckboxSelectMultiple # 多選checkbox ??? FileInput # 文件上傳 ClearableFileInput MultipleHiddenInput # 多隱藏輸入框 SplitDateTimeWidget # 時間分割框(兩個input框) SplitHiddenDateTimeWidget SelectDateWidget
常用的選擇插件
# 單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 # )
在使用選擇標簽時,需要注意choices的選項可以從數據庫中獲取,但是由於是靜態字段 獲取的值無法實時更新,那么需要自定義構造方法從而達到此目的。
from django.forms import Form from django.forms import widgets from django.forms import fields from django.core.validators import RegexValidator 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'].widget.choices = ((1, '上海'), (2, '北京'),) # 或 self.fields['user'].widget.choices = models.Classes.objects.all().value_list('id','caption')
3. 自定義驗證規則
方式1:在字段中自定義validators設計正則匹配
from django.forms import Form from django.forms import widgets from django.forms import fields from django.core.validators import RegexValidator class MyForm(Form): user = fields.CharField( validators=[RegexValidator(r'^[0-9]+$', '請輸入數字'), RegexValidator(r'^159[0-9]+$', '數字必須以159開頭')], )
方式2:自定義規則函數處理數據
import re from django.forms import Form from django.forms import widgets from django.forms import fields 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 PublishForm(Form): title = fields.CharField(max_length=20, min_length=5, error_messages={'required': '標題不能為空', 'min_length': '標題最少為5個字符', 'max_length': '標題最多為20個字符'}, widget=widgets.TextInput(attrs={'class': "form-control", 'placeholder': '標題5-20個字符'})) # 使用自定義驗證規則 phone = fields.CharField(validators=[mobile_validate, ], error_messages={'required': '手機不能為空'}, widget=widgets.TextInput(attrs={'class': "form-control", 'placeholder': u'手機號碼'})) email = fields.EmailField(required=False, error_messages={'required': u'郵箱不能為空','invalid': u'郵箱格式錯誤'}, widget=widgets.TextInput(attrs={'class': "form-control", 'placeholder': u'郵箱'}))
方式3:同時生成多個標簽並進行驗證
from django.forms import Form from django.forms import widgets from django.forms import fields from django.core.validators import RegexValidator ############## 自定義字段 ############## class PhoneField(fields.MultiValueField): def __init__(self, *args, **kwargs): # Define one message for all fields. error_messages = { 'incomplete': 'Enter a country calling code and a phone number.', } # Or define a different message for each field. f = ( fields.CharField( error_messages={'incomplete': 'Enter a country calling code.'}, validators=[ RegexValidator(r'^[0-9]+$', 'Enter a valid country calling code.'), ], ), fields.CharField( error_messages={'incomplete': 'Enter a phone number.'}, validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid phone number.')], ), fields.CharField( validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid extension.')], required=False, ), ) super(PhoneField, self).__init__(error_messages=error_messages, fields=f, require_all_fields=False, *args, **kwargs) def compress(self, data_list): """ 當用戶驗證都通過后,該值返回給用戶 :param data_list: :return: """ return data_list ############## 自定義插件 ############## class SplitPhoneWidget(widgets.MultiWidget): def __init__(self): ws = ( widgets.TextInput(), widgets.TextInput(), widgets.TextInput(), ) super(SplitPhoneWidget, self).__init__(ws) def decompress(self, value): """ 處理初始值,當初始值initial不是列表時,調用該方法 :param value: :return: """ if value: return value.split(',') return [None, None, None]
4. 動態加載數據到form中
在Web應用程序中開發編寫功能時,時常用到獲取數據庫中的數據並將值初始化在HTML中的標簽上。
1.form:
from django.forms import Form from django.forms import widgets from django.forms import fields from django.core.validators import RegexValidator class InitialForm(DForms.Form): username = fields.CharField() user_type = fields.IntegerField( widget=widgets.Select(choices=[]) ) def __init__(self,*args, **kwargs): # 執行父類的構造方法 super(InitialForm,self).__init__(*args, **kwargs) self.fields['user_type'].widget.choices = models.UserType.objects.all().values_list('id','caption')
2.views:
def initial(request): from app01 import forms from app01 import models if request.method == 'GET': nid = request.GET.get('nid') m = models.UserInfo.objects.filter(id=nid).first() dic = {'username': m.name, 'user_type': m.ut_id, 'favor': [1,2,3]} obj = forms.InitialForm(dic) return render(request, 'initial.html', {'obj': obj})
3.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{ obj.username }}
{{ obj.user_type }}
</body>
</html>
分類:
web
