將數據庫與form 組件結合用起來的中間插件html
form組件的難處: 前端
form 能夠實現 對數據的驗證以及 form 的表單標籤的生成git
可是她作不到一點就是沒法將數據庫串聯起來,沒法作到數據的傳回數據庫
好比編輯頁面的時候沒法拿到當前正要被編輯的值django
modelfom 組件在 form組件的基礎上進行升級 :json
自動建立 form 類 (將model類 轉換成 form類)函數
在 from類手動建立的是時候就能夠發現,form 的建立和 model 的數據庫幾乎徹底一致ui
而modelform 能夠幫咱們直接實現這個操做而不在須要手動建立url
直接和 model 對應上,對於 model 的增刪改查會更加的簡單便捷 spa
class Book(models.Model): title=models.CharField(max_length=32) price=models.DecimalField(max_digits=8,decimal_places=2) # 999999.99 date=models.DateField() publish=models.ForeignKey("Publish") authors=models.ManyToManyField("Author") class BookForm(forms.Form): title = forms.CharField(max_length=32,label="書籍名稱") price = forms.DecimalField(max_digits=8, decimal_places=2,label="價格") # 999999.99 date = forms.DateField( label="日期", widget=widgets.TextInput(attrs={"type":"date"}) ) publish=forms.ModelChoiceField(queryset=Publish.objects.all()) authors=forms.ModelMultipleChoiceField(queryset=Author.objects.all())
class BookForm(ModelForm): class Meta: model=Book # 制定要被轉換的表 fields="__all__" # 控制要被轉換的字段 , __all__ 表示全部字段 ,除了 用 __all__ 的時候對多個字段使用的時候用列表的形式 # fields=["title","price"] # 除了 用 __all__ 的時候用字符串形式,對多個字段使用的時候用列表的形式
常見倉鼠:
from django.forms import ModelForm #在視圖函數中,定義一個類,好比就叫StudentList,這個類要繼承ModelForm,在這個類中再寫一個原類Meta(規定寫法,並注意首字母是大寫的) #在這個原類中,有如下屬性(部分): class StudentList(ModelForm): class Meta: # 對應的Model中的類 model =Student # 注意這裏千萬別加 "," 會識別成元組致使報錯 # 字段,若是是__all__,就是表示列出全部的字段 fields = "__all__" # fields = ["name","age"] # 指定顯示某些字段 # 排除的字段 # exclude = ["name","age"] exclude = none# error_messages 錯誤信息
# 自定義錯誤信息(總體錯誤信息from django.core.exceptions import NON_FIELD_ERRORS) error_messages = { '__all__':{}, # 總體的錯誤信息放在這裏 'name':{'required':"用戶名不能爲空",}, # 個別字段的錯誤信息單獨顯示 'age':{'required':"年齡不能爲空",}, }
# widgets 用法,好比把輸入用戶名的input框給爲Textarea# 首先得導入模塊 from django.forms import widgets as wid #由於重名,因此起個別名 widgets = { # 這個widgets只是一個參數名,不要搞混 "name":wid.Textarea(attrs={"class":"c1"}) #還能夠自定義屬性 } # labels 自定義在前端顯示的名字 labels= { "name":"用戶名" } # help_texts 顯示幫助信息 help_texts={ "name":"這裏寫你的名字" }
# field_classes 自定義字段類 field_classes={ 'email':fields.URLField #這裏只能填類,不能加括號,加上括號就變成對象了。
# 這是把郵箱的默認郵箱類自定義成url類了。 }
ps:
在沒有用 form 以及 modelform 以前, 這兩個本質都是同樣,都是保存的就是字符串而已,實際上是沒有意義的
只有 form 以及 modelform 才能夠對他們進行校驗,在這時候 UUIDField , EmailField 之類的纔有意義
由於只有 form 以及 modelform 才能夠將 models.xxxx 轉換成 forms.xxx 的時候進行本身的 is_vaild 方法進行相關的校驗
name = models.CharField
name = models.UUIDField name = models.URLField name = models.EmailField name = models.IPAddressField
若是不用ModelForm,對於要顯示原來的數據,須要挨個取一遍值,
若是ModelForm,只須要加一個 instance=obj(obj是要修改的數據庫的一條數據的對象)就能夠獲得一樣的效果
對當前編輯的對象的數據的取回,在form 組件的時候是沒法操做的
form 類在實例化對象的時候沒法接受參數
modelform 組件能夠 以instance參數接受一個對象
對於數據的編輯更新和新建,modelform 類統一使用 .save() 方法
當 當前的 modelform 對象中沒有 instance參數的時候默認添加一個新對象
當 當前的 modelform 對象中有 instance參數的時候會按照參數的中的對象進行更新操做
(不給對象參數的話怎麼知道要編輯哪個呢?)
def addbook(request): if request.method == "POST": form = BookForm(request.POST) if form.is_valid(): form.save() # form.model.objects.create(request.POST)
return redirect("/books/") else: return render(request, "add.html", locals()) form=BookForm() return render(request, "add.html", locals()) def editbook(request, edit_book_id): # 被編輯的書的對象 edit_book = Book.objects.filter(pk=edit_book_id).first() if request.method == "POST": form = BookForm(request.POST, instance=edit_book) if form.is_valid(): form.save() # edit_book.update(request.POST)
return redirect("/books/") form=BookForm(instance=edit_book) return render(request, "edit.html",locals())
用form方法的時候,驗證功能的函數實際上是寫在BaseForm裏的:UserInfoForm-->繼承了Form--->繼承了BaseForm(is_valid......)
點擊提交的時候,modelform也能夠作驗證。UserInfoModelForm-->繼承了ModelForm--->繼承了BaseModelForm--->繼承了BaseForm(is_valid......)
UserInfoModelForm下面也應該有obj.is_valid(), obj.cleaned_data, obj.errors 等方法。
ModelForm 作驗證的時候與Form方法是同樣的。
咱們能夠像使用Form類同樣自定義局部鉤子方法和全局鉤子方法來實現自定義的校驗規則。
若是咱們不重寫具體字段並設置validators屬性的話,ModelForm是按照模型中字段的validators來校驗的。
modelform 組件在 form 組件的基礎上,保留了 form 組件的所有功能
並且 更加簡單的實現了與model 表的映射建立
而且新增了與model 表的連接得以能夠對當前操做的對象直接操做
ModelForm的全部字段 a. class Meta: model, # 對應Model的哪一個類,哪張表。 fields=None, # 字段 exclude=None, # 排除字段 labels=None, # 提示信息 help_texts=None, # 幫助提示信息 widgets=None, # 自定義插件 error_messages=None, # 自定義錯誤信息(總體錯誤信息from django.core.exceptions import NON_FIELD_ERRORS) field_classes=None # 自定義字段類 (也能夠自定義字段) localized_fields=('birth_date',) # 本地化,如:根據不一樣時區顯示數據 如: 數據庫中 2016-12-27 04:10:57 setting中的配置 TIME_ZONE = 'Asia/Shanghai' USE_TZ = True 則顯示: 2016-12-27 12:10:57 b. 驗證執行過程 is_valid -> full_clean -> 鉤子 -> 總體錯誤 c. 字典字段驗證 def clean_字段名(self): # 能夠拋出異常 # from django.core.exceptions import ValidationError return "新值" d. 用於驗證 model_form_obj = XXOOModelForm() model_form_obj.is_valid() model_form_obj.errors.as_json() model_form_obj.clean() model_form_obj.cleaned_data e. 用於建立 model_form_obj = XXOOModelForm(request.POST) #### 頁面顯示,並提交 ##### # 默認保存多對多 obj = form.save(commit=True) # 不作任何操做,內部定義 save_m2m(用於保存多對多) obj = form.save(commit=False) obj.save() # 保存單表信息 obj.save_m2m() # 保存關聯多對多信息 f. 用於更新和初始化 obj = model.tb.objects.get(id=1) model_form_obj = XXOOModelForm(request.POST,instance=obj) ... PS: 單純初始化 model_form_obj = XXOOModelForm(initial={...})
# 你看不見我,
其實我有偷偷藏起來一份更加詳細的博客 就在這裏了。。。讀書人的事情