django--forms

forms模塊的功能

  1 表單提交驗證前端

  2 生成HTML標籤python

  其餘git

  提交後保留頁面數據正則表達式

建立forms類

  首先從django中引入forms,通常會在application中新建一個文件專門保存form類,由於每個表的驗證都須要一個獨特的forms。數據庫

class SubY(forms.Form):
            user=forms.CharField(min_length=6,error_messages=error_ms,widget=forms.TextInput(attrs={"class":"c1","placeholder":"用戶名"}))
    email = forms.EmailField(error_messages=error_ms)
    shengfen = forms.ChoiceField(choices=[(1,"gaga"),(2,"gaga2")])

  注意:1 這裏的forms字段只能比其相關聯models多不能少django

     2 三者的字段的名字必須一致。model中,HTML中的name屬性值,和forms字段。json

  驗證的使用

 1 def send_email(request):
 2     email = request.POST.get("email")
 3     obj_forms = SubY_send_email(request.POST)
 4     error_info = ReturnInfo()
 5     time_now = datetime.datetime.now()
 6     # print(time_now)
 7     # print(datetime.datetime.now()) # 即便這個時間存在django數據庫中會變成UTC時間,
 8     # 由於django收到的指令是按本身的默認utc時間保存的。
 9     if obj_forms.is_valid():
10         if models.UserMain.objects.filter(email=email).exists():
11             error_info.status_exist = False
12             error_info.error_general = "該郵箱已經被註冊"
13             return HttpResponse(json.dumps(error_info.__dict__))
14         else:
15             try:
16                 obj_email = models.EmailSend_limit.objects.get(email_addr=email)
17             except Exception as e:
18                 models.EmailSend_limit.objects.create(
19                     email_addr=email,
20                     time_last=datetime.datetime.now(),   #  如果在這裏使用now
21                     # 就使得這個字段bond上了timezone信息,
22                     # 再次進行更新的時候,如果沒有tz信息會出現警告並轉換成當初設定的時候的時間
23                     # RuntimeWarning: DateTimeField EmailSend_limit.time_last received
24                     # a naive datetime (2016-12-23 03:03:48.530491) while time zone support is active.進入數據庫時變成了22號
25                     time_first=datetime.datetime.now(),
26                     num_send=1
27                 )
28                 createEmailTemp(email)
29                 error_info.error_general = "郵件已發送"
30                 return HttpResponse(json.dumps(error_info.__dict__))
31             else:
32                 time_first = obj_email.time_first
33                 time_last = obj_email.time_last
34                 time_Hour = time_now - datetime.timedelta(hours=1)
35                 time_first = time_first.replace(tzinfo=None)# time zone info 或者tzinfo=UTC()
36                 # 保存到django中時間會被django加上一個時區信息,而datatime生成的是沒時區信息的時間。
37                 if time_Hour >= time_first:   # 取出的時間是off-aware不能跟now的時間off-naive比較
38                     obj_email.time_last = datetime.datetime.now()
39                     obj_email.time_first = datetime.datetime.now()
40                     obj_email.num_send = 1
41                     obj_email.save()
42                     createEmailTemp(email)
43                     error_info.error_general = "郵件已發送"
44                     return HttpResponse(json.dumps(error_info.__dict__))
45                 else:
46                     time_last = time_last.replace(tzinfo=None)
47                     if (time_now - datetime.timedelta(minutes=1)) < time_last or obj_email.num_send > 10:
48                         error_info.time_limit = False
49                         error_info.error_general = "操做太頻繁,請一小時後重試"
50                         return HttpResponse(json.dumps(error_info.__dict__))
51                     else:
52                         createEmailTemp(email)
53                         obj_email.num_send += 1
54                         time_l = datetime.datetime.now().replace(tzinfo=None)
55                         obj_email.time_last = time_l
56                         print(time_l)
57                         obj_email.save()
58                         error_info.error_general = "郵件已發送"
59                         return HttpResponse(json.dumps(error_info.__dict__))
60     else:
61         error_info.status = False
62         error_info.error_detail = obj_forms.errors.as_data()
63         return HttpResponse(json.dumps(error_info.__dict__,cls=JsonCustomEncoder))

    上述代碼中,第三行建立了一個forms類。而且直接將POST傳入到了obj中。對應的forms類:app

class SubY_send_email(forms.Form):
    email = forms.EmailField(error_messages=error_ms)

    當調用第九行is_valid()方法的時候,此時forms類驗證完畢而且返回一個布爾值。ide

    obj.clean()返回給驗證正確的字段。函數

    obj.errors沒有括號返回給錯誤信息。

      eroors後接有as_data():

{'user': [ValidationError(['不能爲空'])], 'email': [ValidationError(['不能爲空'])]}

      能夠看到data類型中返回有錯誤字段名稱,錯誤類,和自定義的錯誤信息。可是在傳導前端的時候使用json的dumps方法,ValidationError 不是py基本類型 不                        能json。因此建立一個自定義的json來處理:

class JsonCustomEncoder(json.JSONEncoder):
    def default(self,field):
        if isinstance(field, ValidationError):
            return {field.code:field.message}
        else:
            return json.JSONEncoder.default(self,field)
#  上面的函數保證了 在json的過程當中 遇到ValidationError錯誤是進行這個類來解釋
JsonCustomEncoder

      as_json():返回的是json的字符串。直接dumps回去就成。

      as_text():返回成列表的text。不經常使用,默認。

forms類中的字段和插件

  字段和其中參數:

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類型
    ...
View Code

  插件

  插件用於在模塊語言中直接生成對應的HTML標籤。

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
View Code

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# 單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的選項能夠從數據庫中獲取,可是因爲是靜態字段 ***獲取的值沒法實時更新***,那麼須要自定義構造方法從而達到此目的。

方式一:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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' )

方式二:

使用django提供的ModelChoiceField和ModelMultipleChoiceField字段來實現

1
2
3
4
5
6
7
8
9
10
from  django  import  forms
from  django.forms  import  fields
from  django.forms  import  widgets
from  django.forms  import  models as form_model
from  django.core.exceptions  import  ValidationError
from  django.core.validators  import  RegexValidator
 
class  FInfo(forms.Form):
     authors  =  form_model.ModelMultipleChoiceField(queryset = models.NNewType.objects. all ())
     # authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all())

  自定義驗證規則

方式一:

1
2
3
4
5
6
7
8
9
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開頭' )],
     )

方式二:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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 '郵箱' }))

方法三:自定義方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from  django  import  forms
     from  django.forms  import  fields
     from  django.forms  import  widgets
     from  django.core.exceptions  import  ValidationError
     from  django.core.validators  import  RegexValidator
 
     class  FInfo(forms.Form):
         username  =  fields.CharField(max_length = 5 ,
                                     validators = [RegexValidator(r '^[0-9]+$' 'Enter a valid extension.' 'invalid' )], )
         email  =  fields.EmailField()
 
         def  clean_username( self ):
             """
             Form中字段中定義的格式匹配完以後,執行此方法進行驗證
             :return:
             """
             value  =  self .cleaned_data[ 'username' ]
             if  "666"  in  value:
                 raise  ValidationError( '666已經被玩爛了...' 'invalid' )
             return  value

方式四:同時生成多個標籤進行驗證

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
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.
         =  (
             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 ]
相關文章
相關標籤/搜索