Django 學習之From組件

.Form組件介紹

Form組件能夠作的幾件事情:html

  1.用戶請求數據驗證git

  2.自動生成錯誤信息    正則表達式

  3.打包用戶提交的正確信息數據庫

  4.若是其中有一個錯誤了,其餘的正確這,保留上次輸入的內容django

  4.自動建立input標籤並能夠設置樣式瀏覽器

DjangoForms組件主要有如下幾大功能:app

頁面初始化,生成HTML標籤ide

校驗用戶數據(顯示錯誤信息)函數

HTML Form提交保留上次提交數據post

二.Form組件的使用

1.建立模型

 models.py內容爲:

from django.db import models

 

# Create your models here.

class Eep(models.Model):

    name = models.CharField(max_length=32)

    age = models.SmallIntegerField()

    # 最大數爲8  小數位佔2

    salary = models.DecimalField(max_digits=8, decimal_places=2)

2.form組件創建

新建一個編寫form組件的文件my_form.py,根據模型數據表編寫form組件代碼爲:

class EmpForm(forms.Form):

    name = forms.CharField(min_length=5, label="姓名", error_messages={"required": "該字段不能爲空!", "min_length": "用戶名過短。"})

    age = forms.IntegerField(label="年齡",error_messages={"required": "該字段不能爲空!"})

    salary = forms.DecimalField(max_digits=8, decimal_places=2, label="工資",

                                error_messages={"required": "該字段不能爲空!", "max_digits": "數字過長。"})

3.設計url

設計url與視圖對應關係urls.py,而後進入視圖創建相關函數

from django.contrib import admin

from django.urls import path

from app01 import views

 

urlpatterns = [

    path('admin/', admin.site.urls),

    path('add_emp/', views.add_emp),

]

4.視圖函數

此時的視圖函數爲:

from django.shortcuts import render, HttpResponse

from app01 import models

# Create your views here.

from app01.my_forms import EmpForm

 

def add_emp(request):

    if request.method == "GET":

        form = EmpForm()  # 初始化form對象

        return render(request, "add_emp.html", {"form": form})

    else:

        form = EmpForm(request.POST)  # 將數據傳到form對象

        print(form)

        if form.is_valid():  # 進行校驗

            data = form.cleaned_data  # 效驗經過的數據,是字典的類型數據

            print(data)

            models.Eep.objects.create(**data)

            return HttpResponse("OK")

        else:

            print(form.errors)  # 打印錯誤信息

            clean_errors = form.errors.get("__all__")

            #  print(222, clean_errors)

        return render(request, "add_emp.html", {"form": form, "clean_errors": clean_errors})

5.比較Form組件與不使用的模板實現

(1)方式一:本身手動寫HTML頁面

<form action="" method="post">

{#1、本身手動寫HTML頁面#}

    {% csrf_token %}

    <h2>新增信息</h2>

    <p>姓名:<input type="text" name="name"></p>

    <p>年齡:<input type="text" name="age"></p>

    <input type="submit">

</form>

不會有任何提示信息

(2)方式二:

<form action="" method="post">

    {% csrf_token %}

    <h2>新增信息</h2>

{#    方式二: form自帶的as_p#}

    {{ form.as_p }}

    <input type="submit">

</form>

首先會有瀏覽器的自動提示功能:用

(3)方式三:

<form action="" method="post" novalidate>

    {% csrf_token %}

    <h2>新增信息</h2>

{#方式三:手動獲取form對象的字段#}

     <div>

        <label for="id_{{ form.name.name }}">{{ form.name.label }}</label>

        {{ form.name }} <span>{{ form.name.errors.0 }}</span>

    </div>

    <div>

        <label for="id_{{ form.age.name }}">{{ form.age.label }}</label>

        {{ form.age }} <span>{{ form.age.errors.0 }}</span>

    </div>

    <div>

        <label for="id_salary">工資</label>

        {{ form.salary }} <span>{{ form.salary.errors.0 }}{{ clean_errors.0 }}</span>

    </div>

    <div>

        <label for="id_r_salary">{{ form.r_salary.label }}</label>

        {{ form.r_salary }} <span>{{ form.r_salary.errors.0 }}{{ clean_errors.0 }}</span>

    </div>

    <input type="submit">

</form>

 

實現的的效果爲:

(4)方式四:4的效果和3相同

<form action="" method="post" novalidate>

    {% csrf_token %}

    <h2>新增信息</h2>

{#    方式四:#}

{#    for循環展現全部字段 , 循環的是form對象中的字段值   #}

 

    {% for field in form %}

{#        field == form.age#}

        <div>

            <label for="id_{{ field.name }}">{{ field.label }}</label>

            {{ field }} <span>{{ field.errors.0 }}</span>

        </div>

    {% endfor %}

    <input type="submit">

</form>

 

分析:

若是訪問視圖的是一個GET 請求,它將建立一個空的表單實例並將它放置到要渲染的模板的上下文中。這是咱們在第一個訪問該URL 時預期發生的狀況。

若是表單的提交使用POST 請求,那麼視圖將再次建立一個表單實例並使用請求中的數據填充它:form = NameForm(request.POST)。這叫作綁定數據至表單(它如今是一個綁定的表單)。

咱們調用表單的is_valid()方法;若是它不爲True,咱們將帶着這個表單返回到模板。這時表單再也不爲空(未綁定),因此HTML 表單將用以前提交的數據填充,而後能夠根據要求編輯並改正它。

若是is_valid()True,咱們將可以在cleaned_data 屬性中找到全部合法的表單數據。在發送HTTP 重定向給瀏覽器告訴它下一步的去向以前,咱們能夠用這個數據來更新數據庫或者作其它處理。

 

注意: form = TeacherForm()  #沒有參數,只是一個input

    form = TeacherForm(data=request.POST) # 數據和規則放置一塊兒 (添加的時候用)

    form = TeacherForm(initial={'username':obj.username,

'password':obj.password,'email':obj.email})  

  # 顯示input,而且將數據庫中的默認值填寫到input框中 (編輯的時候用)

最後在使用正常的狀況下成功插入正常數據三條:

附: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類型
    ...

Django內置字段
View Code

三.Form組件之鉤子HOOK

1.局部鉤子

將下面這個函數加到form中的類中:

# 局部鉤子clean_字段

def clean_name(self):  # 局部鉤子

    val = self.cleaned_data.get("name")

 

    if val.isdigit():

        raise ValidationError("用戶不能是純數字")

    elif models.Eep.objects.filter(name=val):

        raise ValidationError("用戶已存在")

    else:

        # 都知足,返回

        return val

 

這樣就能實現局部鉤子的效果:

2.全局鉤子

在使用方式3的狀況下,首先在html文件中加入標籤數據:

    <div>

        <label for="id_r_salary">{{ form.r_salary.label }}</label>

        {{ form.r_salary }} <span>{{ form.r_salary.errors.0 }}{{ clean_errors.0 }}</span>

    </div>

 

而後在my_formEmpForm類中加入:

r_salary = forms.DecimalField(max_digits=8, decimal_places=2, label="請再輸入工資",

              error_messages={"required": "該字段不能爲空!", "max_digits": "數字過長。"})

還有在其後面加上全局鉤子函數:

# 全局鉤子直接clean

def clean(self):  # 全局鉤子 確認兩次輸入的工資是否一致。

    val = self.cleaned_data.get("salary")

    r_val = self.cleaned_data.get("r_salary")

 

    if val == r_val:

        return self.cleaned_data

    else:

        raise ValidationError("請確認工資是否一致。")

 

由於數據庫的表中是沒有r_salary的字段的,在data寫入數據表以前須要將其刪除r_salary的相關數據:即視圖函數刪除數據:data.pop("r_salary")

進行測試:

最後工資相同才插入數據:

相關文章
相關標籤/搜索