1. 程式人生 > >Django form&ModelForm

Django form&ModelForm

rabl pil direct art display 進行 mes reg 列表

django中的Form功能操作:

  • 驗證用戶請求

  • 生成HTML標簽

    (保留上一次提交的數據)

比如用戶註冊信息驗證:用戶名不允許為空、密碼最短6位,如果自己寫需要些很多,比較麻煩,而Django form提供了特別便捷的實現方式

Form表單驗證模板模板是一個類,創建如下:

1、初始form,創建form

技術分享
from django import forms
class FM(forms.Form):
    # 只關心處理自己定義的form表單數據,惡意攻擊定義的數據不處理
    user = forms.CharField()
    pwd = forms.CharField()  #
這裏的變量名必須和html form裏的name保持一致 email = forms.EmailField() def fm(request): if request.method == "GET": return render(request, "fm.html") elif request.method == "POST": # 獲取用戶所有數據,每條數據請求的驗證 # 成功 --> 獲取所有的正確信息;失敗 --> 顯示錯誤信息 obj = FM(request.POST) r1
= obj.is_valid() if r1: # 返回的正確信息 print(obj.cleaned_data) else: # 返回的錯誤信息 print(obj.errors) print(obj.errors.as_json()) return redirect(/fm/)
views.py

技術分享
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"
> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> </head> <body> <form action="/fm/" method="POST"> {% csrf_token %} <input type="text" name="user"> <input type="text" name="pwd"> <input type="text" name="email"> <input type="submit" value="提交" /> </form> </body> </html>
fm.html

<ul class="errorlist"><li>email<ul class="errorlist"><li>This field is required.</li></ul></li><li>pwd<ul class="errorlist"><li>This field is required.</li></ul></li><li>user<ul class="errorlist"><li>This field is required.</li></ul></li></ul>
{"email": [{"message": "This field is required.", "code": "required"}], "pwd": [{"message": "This field is required.", "code": "required"}], "user": [{"message": "This field is required.", "code": "required"}]}

上面的錯誤信息為英文,能不能自定制呢?

2、自定制form錯誤信息,前端顯示

技術分享
from django import forms
class FM(forms.Form):
    # 只關心處理自己定義的form表單數據,惡意攻擊定義的數據不處理
    user = forms.CharField(error_messages={required:用戶名不能為空})
    pwd = forms.CharField(
        max_length=12,
        min_length=6,
        error_messages={required:密碼不能為空,min_length:密碼長度不能小於6,max_length:密碼長度不能大於12}
    )
    email = forms.EmailField(error_messages={required:用戶名不能為空,invalid:郵箱格式錯誤})

def fm(request):
    if request.method == "GET":
        return render(request, "fm.html")
    elif request.method == "POST":
        obj = FM(request.POST)
        r1 = obj.is_valid()
        if r1:  # 返回的正確信息
            print(obj.cleaned_data)
        else:   # 返回的錯誤信息
            # ErrorDict
            # print(obj.errors[‘user‘][0])
            # print(obj.errors.as_json())
            return render(request,fm.html,{obj:obj})
        return render(request,fm.html)
views.py

技術分享
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="x-ua-compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Title</title>
</head>
<body>
    <form action="/fm/" method="POST">
        {% csrf_token %}
        <p><input type="text" name="user"> {{ obj.errors.user.0 }}</p>
        <p><input type="text" name="pwd"> {{ obj.errors.pwd.0 }}</p>
        <p><input type="text" name="email"> {{ obj.errors.email.0 }}</p>
        <input type="submit" value="提交" />
    </form>
</body>
</html>
fm.html

3、保留上一次提交的數據,自動生成html標簽

views裏面不僅能幫我們生成錯誤信息,還能幫我們生成html標簽。

技術分享
def fm(request):
    if request.method == "GET":
        obj = FM()  # 自動生成html時,get這裏也需要創建對象
        return render(request, "fm.html",{obj:obj})
    elif request.method == "POST":
        obj = FM(request.POST)
        r1 = obj.is_valid()
        if r1:  # 返回的正確信息
            print(obj.cleaned_data)  # 這是個字典,註冊直接下面那一句就成功了
            # models.UserInfo.objects.create(**obj.cleaned_data)
        else:   # 返回的錯誤信息
            return render(request,fm.html,{obj:obj})
        return render(request,fm.html)
views.py

技術分享
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="x-ua-compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Title</title>
</head>
<body>
        <form action="/fm/" method="POST">
        {% csrf_token %}
        <p>{{ obj.user }} {{ obj.errors.user.0 }}</p>
        <p>{{ obj.pwd }} {{ obj.errors.pwd.0 }}</p>
        <p>{{ obj.email }} {{ obj.errors.email.0 }}</p>
        <input type="submit" value="提交" />
    </form>
</body>
</html>
fm.html

4、更簡潔的html標簽生成方法

這裏生成雖然方便,但是可定制化不如上面高。

  • obj.as_p
  • obj.as_ul
  • obj.as_table

可以把上面html裏的form改為:

    <form action="/fm/" method="POST">
        {% csrf_token %}
        {{ obj.as_p }}
        <input type="submit" value="提交" />
    </form>
    <form action="/fm/" method="POST">
        {% csrf_token %}
        {{ obj.as_ul }}
        <input type="submit" value="提交" />
    </form>
    <form action="/fm/" method="POST">
        {% csrf_token %}
        <table>
            {{ obj.as_table }}
        </table>  
        <input type="submit" value="提交" />
    </form>

5、自定義樣式

form類裏面的字段,只有一個功能,就是驗證客戶端發過來的數據。生成html的功能做不了。

但是怎麽生成的html標簽呢,在charfield裏面有個插件,插件生成的。在其源碼裏做了html字符串的拼接返回。

from django import forms
from django.forms import widgets  # 插件在這裏面
class FM(forms.Form):
    # 字段本身只做驗證
    user = forms.CharField(         # 修改html標簽,並指定樣式##############
        error_messages={‘required‘:‘用戶名不能為空‘},
        widget=widgets.Textarea(attrs={‘class‘:‘c1‘}),  # 頁面再看就是textarea了
        label="用戶名"
    )
    pwd = forms.CharField(
        max_length=12,
        min_length=6,
        error_messages={‘required‘:‘密碼不能為空‘,‘min_length‘:‘密碼長度不能小於6‘,‘max_length‘:‘密碼長度不能大於12‘},
        widget=widgets.PasswordInput  # 密碼密文顯示,如果自定義樣式也可加上(attrs……)
    )
    email = forms.EmailField(error_messages={‘required‘:‘用戶名不能為空‘,‘invalid‘:‘郵箱格式錯誤‘})

  

而字段都在from django.forms import fields裏面,所以上面的forms可以改用fields

email = fields.EmailField()

前端<p>{{ obj.user.label }}{{ obj.user }} {{ obj.errors.user.0 }}</p>

插件裏面input、checkbox、select、redio等全部都有

6、form 內置字段

技術分享
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

說一下上面的ChoiceField,它主要做選項用的

    city = fields.ChoiceField(
        choices=[(0,‘上海‘),(1,‘廣州‘)]
    )
    city2 = fields.MultipleChoiceField(
        choices=[(0,‘上海‘),(1,‘廣州‘)]
    )

  常用選擇插件

技術分享
# 單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
# )
View Code

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

自定義
    -- 字段(校驗)
    - 插件(生成HTML

7、初始化操作

在Web應用程序中開發編寫功能時,時常用到獲取數據庫中的數據並將值初始化在HTML中的標簽上。

def fm(request):
    if request.method == "GET":
        dic = {
            "user":‘r1‘,
            "pwd":‘123456‘,
            "email":‘[email protected]‘,
            "city":1,
            "city2":[1,2],
        }
        obj = FM(initial=dic)  # 初始化
        return render(request, "fm.html",{‘obj‘:obj})

  

參考博客

參考博客

Django form&ModelForm