Form組件能夠作的幾件事情:html
1.用戶請求數據驗證git
2.自動生成錯誤信息 正則表達式
3.打包用戶提交的正確信息數據庫
4.若是其中有一個錯誤了,其餘的正確這,保留上次輸入的內容django
4.自動建立input標籤並能夠設置樣式瀏覽器
Django的Forms組件主要有如下幾大功能:app
頁面初始化,生成HTML標籤ide
校驗用戶數據(顯示錯誤信息)函數
HTML Form提交保留上次提交數據post
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)
新建一個編寫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": "數字過長。"})
設計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})
(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內置字段
將下面這個函數加到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
這樣就能實現局部鉤子的效果:
在使用方式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_form的EmpForm類中加入:
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")
進行測試:
最後工資相同才插入數據: