參考博客:html
http://www.javashuo.com/article/p-vuqaekra-ma.htmlpython
http://www.cnblogs.com/wupeiqi/articles/6144178.htmlgit
Form組件 - 對用戶請求的驗證 - AJax - Form - 生成HTML代碼 a. 建立一個類 b. 類中建立字段(包含正則表達式) c. GET obj = Fr() obj.user = > 自動生成HTML d. POST obj = Fr(request.POST) if obj.is_valid(): obj.cleaned_data else: obj.errors return .... obj
Form組件能夠作的幾件事情:正則表達式
一、用戶請求數據驗證數據庫
二、自動生成錯誤信息 django
三、打包用戶提交的正確信息瀏覽器
四、若是其中有一個錯誤了,其餘的正確這,保留上次輸入的內容app
五、生成HTML標籤dom
一、建立規則ide
class Foo(Form): #必須繼承 username = xxx password = xxx email = xxx 注意這裏的字段必須和input的name字段一致
二、數據和規則進行匹配
先導入view.py
from django.forms import Form from django.forms import fields from django.forms import widgets
from django.shortcuts import render,redirect from app01 import models # Create your views here. from django.forms import Form from django.forms import fields from django.forms import widgets # 一、建立規則 class TeacherForm(Form): #必須繼承Form # 建立字段,本質上是正則表達式 username = fields.CharField( required=True, #必填字段 error_messages={"required":"用戶名不能爲空!!"}, #顯示中文錯誤提示 widget=widgets.TextInput(attrs={"placeholder":"用戶名","class":"form-control"}) #自動生成input框 ) password = fields.CharField(required=True, error_messages={'required': '密碼不能爲空'}, widget=widgets.TextInput(attrs={'placeholder': '密碼', 'class': 'form-control'})) # 不能爲空 email = fields.EmailField( required=True, error_messages={"required":"郵箱不能爲空!!","invalid":"無效的郵箱"}, widget=widgets.EmailInput(attrs={"placeholder": "郵箱", "class": "form-control"}) # 自動生成input框 ) #不能爲空且郵箱格式要一致 # 二、使用規則:將數據和規則進行匹配 def teacherindex(request): teacher_obj = models.UserInfo.objects.all() # print(teacher_obj) return render(request,"teacherindex.html",{"teacher_obj":teacher_obj}) def add(request): if request.method=="GET": form = TeacherForm() #只是讓顯示一個input框 return render(request,"add.html",{"form":form }) else: form = TeacherForm(data=request.POST) # print(form) #<QuerySet [<UserInfo: UserInfo object>, <UserInfo: UserInfo object>, <UserInfo: UserInfo object>]> if form.is_valid():# 開始驗證 # print('執行成功',form.cleaned_data) # 全部匹配成功,字典 # {'username': 'asd', 'password': 'sdf', 'email': 'sadf@live.com','ut_id':1} form.cleaned_data['ut_id'] = 1 #要分的清是班主任仍是講師 models.UserInfo.objects.all().create(**form.cleaned_data) return redirect("/teacherindex/") else: # print("=====?",form.errors,type(form.errors))#返回失敗的結果 # print(form.errors["username"][0]) #拿到返回失敗的結果,渲染到頁面 return render(request,"add.html",{"form":form})
html
{% block right %} <h1>添加老師信息</h1> <hr> <form method="post" novalidate> {% csrf_token %} <p>姓名:{{ form.username }}</p>{{ form.errors.username.0 }} <p>密碼:{{ form.password }}</p>{{ form.errors.password.0 }} <p>郵箱:{{ form.email }}</p>{{ form.errors.email.0 }} <p><input type="submit" value="提交"></p> </form> {% endblock %}
若是訪問視圖的是一個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框中 (編輯的時候用)
簡單實例(一)
class F1Form(forms.Form): user = fields.CharField(required=True, max_length=18, min_length=6, error_messages={'required':'用戶名不能爲空','max_length': '太長了', 'min_length':'過短了'}, widget=widgets.TextInput(attrs={'placeholder':"用戶名"}) ) pwd = fields.CharField(required=True, min_length=9, error_messages={'min_length': "過短了"}) age = fields.IntegerField(required=True) email = fields.EmailField(required=True,min_length=8, error_messages={'invalid': "格式錯誤"}) def f1(request): if request.method == 'GET': obj = F1Form() return render(request, 'f1.html', {'obj': obj}) if request.method == "POST": obj = F1Form(request.POST) if obj.is_valid(): print("驗證成功", obj.cleaned_data) return redirect('http://www.xiaohuar.com') else: print("驗證失敗", obj.errors) return render(request, 'f1.html', {"obj": obj})
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/f1/" method="post" novalidate> {% csrf_token %} <p>{{ obj.user }}{{ obj.errors.user.0 }}</p> <p>{{ obj.pwd }}{{ obj.errors.pwd.0 }}</p> <p>{{ obj.age }}{{ obj.errors.age.0 }}</p> <p>{{ obj.email }}{{ obj.errors.email.0 }}</p> <input type="submit" value="提交"> </form> </body> </html>
簡單實例(二)
"""django_form URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/2.1/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: path('', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin from django.urls import path,re_path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('users/', views.users), path('add_user/', views.add_user), re_path(r'edit_user-(\d+)/', views.edit_user), ]
from django.shortcuts import render, redirect from app01 import models from app01 import forms # Create your views here. def users(request): obj_list = models.UserInfo.objects.all() return render(request, "user.html", {"obj_list": obj_list}) def add_user(request): if request.method == "GET": obj = forms.UserForm() return render(request, "add_user.html", {"obj": obj}) if request.method == "POST": obj = forms.UserForm(request.POST) if obj.is_valid(): models.UserInfo.objects.create(**obj.cleaned_data) return redirect("/users/") else: return render(request, "add_user.html", {"obj": obj}) def edit_user(request,nid): if request.method == "GET": data = models.UserInfo.objects.filter(id=nid).first() obj = forms.UserForm({'username': data.username,'email': data.email}) return render(request, "edit_user.html", {'obj': obj, 'nid': nid}) else: obj = forms.UserForm(request.POST) if obj.is_valid(): models.UserInfo.objects.filter(id=nid).update(**obj.cleaned_data) return redirect("/users/") else: return render(request, 'edit_user.html', {'obj': obj, 'nid': nid})
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <a href="/add_user/">添加</a> {% for item in obj_list %} <li> {{ item.id }}--{{ item.username }}--{{ item.email }} <a href="/edit_user-{{ item.id }}/">編輯</a> </li> {% endfor %} </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/add_user/" method="post" novalidate> {% csrf_token %} <p>{{ obj.username }}{{ obj.errors.username.0 }}</p> <p>{{ obj.email }}{{ obj.errors.email.0 }}</p> <input type="submit" value="提交"> </form> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/edit_user-{{ nid }}/" method="post" novalidate> {% csrf_token %} <p>{{ obj.username }}{{ obj.errors.username.0 }}</p> <p>{{ obj.email }}{{ obj.errors.email.0 }}</p> <input type="submit" value="提交"> </form> </body> </html>
from django import forms as dforms
from django.forms import fields
class UserForm(dforms.Form):
username = fields.CharField()
email = fields.EmailField()
每一個表單字段都有一個對應的Widget
類,它對應一個HTML 表單Widget
,例如<input type="text">
。
在大部分狀況下,字段都具備一個合理的默認Widget。例如,默認狀況下,CharField
具備一個TextInput Widget
,它在HTML 中生成一個<input type="text">
。
無論表單提交的是什麼數據,一旦經過調用is_valid()
成功驗證(is_valid()
返回True
),驗證後的表單數據將位於form.cleaned_data
字典中。這些數據已經爲你轉換好爲Python 的類型。
注:此時,你依然能夠從request.POST
中直接訪問到未驗證的數據,可是訪問驗證後的數據更好一些。
在上面的聯繫表單示例中,is_married將是一個布爾值。相似地,IntegerField
和FloatField
字段分別將值轉換爲Python 的int
和float
。
實例:
from django.forms import Form from django.forms import widgets from django.forms import fields class MyForm(Form): user = fields.CharField( widget=widgets.TextInput(attrs={'id': 'i1', 'class': 'c1'}) ) gender = fields.ChoiceField( choices=((1, '男'), (2, '女'),), initial=2, widget=widgets.RadioSelect ) city = fields.CharField( initial=2, widget=widgets.Select(choices=((1,'上海'),(2,'北京'),)) ) pwd = fields.CharField( widget=widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True) )
from django.shortcuts import render, redirect from .forms import MyForm def index(request): if request.method == "GET": obj = MyForm() return render(request, 'index.html', {'form': obj}) elif request.method == "POST": obj = MyForm(request.POST, request.FILES) if obj.is_valid(): 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.user.errors }}</p> <p>{{ form.gender }} {{ form.gender.errors }}</p> <p>{{ form.city }} {{ form.city.errors }}</p> <p>{{ form.pwd }} {{ form.pwd.errors }}</p> <input type="submit"/> </form>
obj = forms.MyForm() txt = "<input type='text'/>" from django.utils.safestring import mark_safe txt = mark_safe(txt) return render(request, "index.html", {'obj': obj, 'txt':txt}) #或者在html文件加{{ txt|safe }},使用以上方式不須要再加'|safe'
建立Form類時,主要涉及到 【字段】 和 【插件】,字段用於對用戶請求數據的驗證,插件用於自動生成HTML;
1 Field 2 required=True, 是否容許爲空 3 widget=None, HTML插件 4 label=None, 用於生成Label標籤或顯示內容 5 initial=None, 初始值 6 help_text='', 幫助信息(在標籤旁邊顯示) 7 error_messages=None, 錯誤信息 {'required': '不能爲空', 'invalid': '格式錯誤'} 8 show_hidden_initial=False, 是否在當前插件後面再加一個隱藏的且具備默認值的插件(可用於檢驗兩次輸入是否一直) 9 validators=[], 自定義驗證規則 10 localize=False, 是否支持本地化 11 disabled=False, 是否能夠編輯 12 label_suffix=None Label內容後綴 13 14 15 CharField(Field) 16 max_length=None, 最大長度 17 min_length=None, 最小長度 18 strip=True 是否移除用戶輸入空白 19 20 IntegerField(Field) 21 max_value=None, 最大值 22 min_value=None, 最小值 23 24 FloatField(IntegerField) 25 ... 26 27 DecimalField(IntegerField) 28 max_value=None, 最大值 29 min_value=None, 最小值 30 max_digits=None, 總長度 31 decimal_places=None, 小數位長度 32 33 BaseTemporalField(Field) 34 input_formats=None 時間格式化 35 36 DateField(BaseTemporalField) 格式:2015-09-01 37 TimeField(BaseTemporalField) 格式:11:12 38 DateTimeField(BaseTemporalField)格式:2015-09-01 11:12 39 40 DurationField(Field) 時間間隔:%d %H:%M:%S.%f 41 ... 42 43 RegexField(CharField) 44 regex, 自定製正則表達式 45 max_length=None, 最大長度 46 min_length=None, 最小長度 47 error_message=None, 忽略,錯誤信息使用 error_messages={'invalid': '...'} 48 49 EmailField(CharField) 50 ... 51 52 FileField(Field) 53 allow_empty_file=False 是否容許空文件 54 55 ImageField(FileField) 56 ... 57 注:須要PIL模塊,pip3 install Pillow 58 以上兩個字典使用時,須要注意兩點: 59 - form表單中 enctype="multipart/form-data" 60 - view函數中 obj = MyForm(request.POST, request.FILES) 61 62 URLField(Field) 63 ... 64 65 66 BooleanField(Field) 67 ... 68 69 NullBooleanField(BooleanField) 70 ... 71 72 ChoiceField(Field) 73 ... 74 choices=(), 選項,如:choices = ((0,'上海'),(1,'北京'),) 75 required=True, 是否必填 76 widget=None, 插件,默認select插件 77 label=None, Label內容 78 initial=None, 初始值 79 help_text='', 幫助提示 80 81 82 ModelChoiceField(ChoiceField) 83 ... django.forms.models.ModelChoiceField 84 queryset, # 查詢數據庫中的數據 85 empty_label="---------", # 默認空顯示內容 86 to_field_name=None, # HTML中value的值對應的字段 87 limit_choices_to=None # ModelForm中對queryset二次篩選 88 89 ModelMultipleChoiceField(ModelChoiceField) 90 ... django.forms.models.ModelMultipleChoiceField 91 92 93 94 TypedChoiceField(ChoiceField) 95 coerce = lambda val: val 對選中的值進行一次轉換 96 empty_value= '' 空值的默認值 97 98 MultipleChoiceField(ChoiceField) 99 ... 100 101 TypedMultipleChoiceField(MultipleChoiceField) 102 coerce = lambda val: val 對選中的每個值進行一次轉換 103 empty_value= '' 空值的默認值 104 105 ComboField(Field) 106 fields=() 使用多個驗證,以下:即驗證最大長度20,又驗證郵箱格式 107 fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),]) 108 109 MultiValueField(Field) 110 PS: 抽象類,子類中能夠實現聚合多個字典去匹配一個值,要配合MultiWidget使用 111 112 SplitDateTimeField(MultiValueField) 113 input_date_formats=None, 格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y'] 114 input_time_formats=None 格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M'] 115 116 FilePathField(ChoiceField) 文件選項,目錄下文件顯示在頁面中 117 path, 文件夾路徑 118 match=None, 正則匹配 119 recursive=False, 遞歸下面的文件夾 120 allow_files=True, 容許文件 121 allow_folders=False, 容許文件夾 122 required=True, 123 widget=None, 124 label=None, 125 initial=None, 126 help_text='' 127 128 GenericIPAddressField 129 protocol='both', both,ipv4,ipv6支持的IP格式 130 unpack_ipv4=False 解析ipv4地址,若是是::ffff:192.0.2.1時候,可解析爲192.0.2.1, PS:protocol必須爲both才能啓用 131 132 SlugField(CharField) 數字,字母,下劃線,減號(連字符) 133 ... 134 135 UUIDField(CharField) uuid類型 136 ...
注: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')
# 單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')
self.fields語句必定要在調用父類構造函數以後,由於調用父類構造函數以後纔有字段fields
方式二:
使用django提供的ModelChoiceField和ModelMultipleChoiceField字段來實現
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())
Form重點:
- 字段
用於保存正則表達式
ChoiceField *****
MultipleChoiceField
CharField
IntegerField
DecimalField
DateField
DateTimeField
EmailField
GenericIPAddressField
FileField
RegexField
實例
from django.shortcuts import render from django import forms from django.forms import fields from django.forms import widgets class TestForm(forms.Form): user = fields.CharField( required=True, # 是否必填 max_length=12, # 最大長度 min_length=3, # 最小長度 error_messages={}, # 錯誤提示 #widget = widgets.Select(), # 定製HTML插件 label='用戶名', initial='請輸入用戶', help_text='asdfasdf', show_hidden_initial=False, # validators=[] disabled=True, label_suffix='->' # obj.as_p 會顯示出來 ) age = fields.IntegerField( label='年齡', max_value= 12, min_value=5, error_messages={ 'max_value':'太大了' } ) email = fields.EmailField( label='郵箱' ) img = fields.FileField() city = fields.TypedChoiceField( coerce=lambda x: int(x), choices=[(1,'上海',),(2,'北京'),(3,'沙河'),], initial=2 ) bobby = fields.MultipleChoiceField( choices=[(1,'剛娘'),(2,'鐵娘'),(3,'鋼彈')], initial=[1,2] ) xoo = fields.FilePathField( path='app01' ) def test(request): if request.method == 'GET': #obj = TestForm({'city':3}) obj = TestForm() return render(request,'test.html',{'obj':obj}) else: obj = TestForm(request.POST,request.FILES) obj.is_valid() print(obj.cleaned_data) return render(request, 'test.html', {'obj': obj})
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form method="POST" action="/test/" novalidate enctype="multipart/form-data"> {% csrf_token %} <p>{{ obj.user.label }}{{ obj.user }}</p> <p>{{ obj.age.label }}{{ obj.age }}{{ obj.errors.age.0 }}</p> <p>{{ obj.email.label }}{{ obj.email }}</p> <p>{{ obj.img.label }}{{ obj.img }}</p> <p>{{ obj.city.label }}{{ obj.city }}</p> <p>{{ obj.bobby.label }}{{ obj.bobby }}</p> <p>{{ obj.xoo.label }}{{ obj.xoo }}</p> <input type="submit" value="提交"/> </form> </body> </html>
特殊的單選或多選時,數據源是否能實時更新?
from app01 import models from django.forms.models import ModelChoiceField class LoveForm(forms.Form): price = fields.IntegerField() user_id = fields.IntegerField( # widget=widgets.Select(choices=[(0,'alex'),(1,'劉皓宸'),(2,'楊建'),]) widget=widgets.Select() ) user_id2 = ModelChoiceField( queryset=models.UserInfo.objects.all(), to_field_name='id' ) def __init__(self,*args,**kwargs): # 拷貝全部的靜態字段,複製給self.fields super(LoveForm,self).__init__(*args,**kwargs) self.fields['user_id'].widget.choices = models.UserInfo.objects.values_list('id', 'username') def love(request): obj = LoveForm() return render(request,'love.html',{'obj':obj})
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p>價格:{{ obj.price }}</p> <p>姓名:{{ obj.user_id }}</p> <p>姓名:{{ obj.user_id2 }}</p> </body> </html>
注意:依賴models中的str方法