Model、Form、ModelForm的比較
阿新 • • 發佈:2019-05-16
關系 Nid edi 分享 報錯 數據 而在 textarea ssa
本節內容:
1:Model
2:Form
3:Model Form
1 2 3 |
http: //www .cnblogs.com /wupeiqi/articles/6144178 .html 武sir:Form組件
http: //www .cnblogs.com /wupeiqi/articles/6216618 .html 武sir:Model
http: //www .cnblogs.com /wupeiqi/articles/6229414 .html 武sir:ModelForm
|
Model ==> 強大的數據庫操作,弱小的數據驗證。
Form ==>強大的數據驗證
ModelForm ===>二者結合,強大的數據驗證,適中的數據庫操作。在ModelForm是能夠封裝一個model對象。
1:Model
對於Model來說,他的驗證是需要自己去創建一個model對象,然後去進行判斷
model: 針對單一字段 :full_clean 針對多個的字段: clean full_clean -- >字段正則判定 -- >clean方法(鉤子) 他是沒有最終產物
views:
def fm(request): obj= models.News(title=‘root‘) ##full_clean就進行了驗證,如果要是有errors的話,就直接報錯,所以在進行驗證的時候,我們要自己做try判斷 obj.full_clean() ##進行model的驗證。裏面的def clean 方法 obj.save() ##報錯 django.core.exceptions.ValidationError: {‘__all__‘: [‘title不能是root‘]} return render(request,"form.html",locals())
models:
from django.db import models from django.core.exceptions import ValidationError class News(models.Model): title = models.CharField(max_length=32) ##驗證錯誤會輸出到errors中去 def clean(self): if self.title == "root": raise ValidationError("title不能是root")
model的源碼分析:
def full_clean(self, exclude=None, validate_unique=True): """ Call clean_fields(), clean(), and validate_unique() on the model. Raise a ValidationError for any errors that occur. """ errors = {} if exclude is None: exclude = [] else: exclude = list(exclude) try: self.clean_fields(exclude=exclude) ####執行單個字段的驗證 except ValidationError as e: errors = e.update_error_dict(errors) # Form.clean() is run even if other validation fails, so do the # same with Model.clean() for consistency. try: self.clean() ####執行clean的方法驗證 except ValidationError as e: errors = e.update_error_dict(errors) ###如果錯誤,把錯誤添加到errors中 # Run unique checks, but only for fields that passed validation. if validate_unique: for name in errors: if name != NON_FIELD_ERRORS and name not in exclude: exclude.append(name) try: self.validate_unique(exclude=exclude) except ValidationError as e: errors = e.update_error_dict(errors) if errors: ###如果有錯誤,就直接報錯了,so 我們要自己去views視圖中去判斷,try raise ValidationError(errors)View Code
2:Form
有著強大的驗證功能: 具體看源碼。
對於Form來說,是當一個請求來了,直接進行post數據的驗證,如果是錯誤會有一個obj.errors的錯誤對應。
Form :有強大的驗證 針對單一字段的: full_clean 自定義針對單一字段的: clean_username 針對多個字段的: clean 【or】port_clean (這個是不能出現異常,只能添加異常) is_valid() -- >full_clean () --> -->每個字段的正則,每個字段clean_字段名() -->clean_form -->clean(鉤子) -->_post_clean(鉤子) 驗證後的產物:clean_date 或obj.errors
Form中要獲取數據庫的實時數據:
兩種方式:
?1 |
第二種方式,雖然是可以用但是它的可定制性差。是需要依賴model的
|
瀏覽器中:顯示
3:ModelForm
Model、Form、ModelForm三者的結合:
在公司比較大的時候:比如說:
models文件是放在A項目中
forms是放在B項目中
froms是沒辦法導入models中的數據的。
我們就讓Form單獨的做數據驗證,而model就單純的做數據庫操作各司其職是完美的。
但是dajngo還存在了一種叫ModelForm的東西,他是結合了model和Form的功能。
Form和ModelForm的繼承關系:
Form: 繼承關系: UserForm -- > Form -- >BaseForm ModelForm: 繼承關系: NewsModelForm -->ModelForm -->BaseModelForm -->BaseForm 所以modelForm和Form是有同一個祖宗的,Form中的BaseForm的功能,ModelForm也一樣可以使用。
ModelForm的簡單使用:
from django.db import models from django.core.exceptions import ValidationError class User_Type(models.Model): name = models.CharField(max_length=32) def __str__(self): return self.name class Tags(models.Model): name = models.CharField(max_length=32) def __str__(self): return self.name class News(models.Model): title = models.CharField(max_length=32) type = models.ForeignKey(User_Type,on_delete=models.CASCADE,blank=True,null=True) tag = models.ManyToManyField(Tags) ##驗證錯誤會輸出到errors中去 def clean(self): if self.title == "root": raise ValidationError("title不能是root")model
from django.forms import Form ##Form要繼承的 from django.forms import ModelForm ##ModelForm繼承 from web import models class NewsModelForm(ModelForm): class Meta: model = models.News ##裏面必須要有一個model,因為他是對每個models類做增刪改查的 fields = "__all__" ##指定了類,要需要指定要處理哪幾個字段 __all__是全部字段 def mf(request): if request.method == "GET": obj = NewsModelForm() if request.method == "POST": obj = NewsModelForm(data=request.POST) ##傳入進行驗證 if obj.is_valid(): #models.News.objects.create(**obj.cleaned_data) ##以前Form的時候添加數據要這樣寫 obj.save() ##modelform現在可以直接save就可以,save的時候可以保存一對多、多對多的數據 else: print(obj.errors) return render(request, "mf.html", locals())
template: [是不需要執行上面的什麽__init__方法、和第二種方法]直接就可以實時了。
<form action="" method="post"> {% csrf_token %} {{ obj.as_p }} <input type="submit"> </form>
ModelForm的另一個功能:修改
urls:
?1 |
re_path( ‘edit-(\d+).html‘ ,views.edit)
|
views:
class NewsModelForm(ModelForm): class Meta: model = models.News ##裏面必須要有一個model,因為他是對每個models類做增刪改查的 fields = "__all__" ##指定了類,要需要指定要處理哪幾個字段 __all__是全部字段 def edit(request,nid): if request.method == "GET": model_obj = models.News.objects.get(id=nid) ##獲取model對象 obj = NewsModelForm(instance=model_obj) else: model_obj = models.News.objects.get(id=nid) obj = NewsModelForm(request.POST,instance=model_obj) ##修改的時候是需要instance 的!如果沒有則默認就是增加數據的 if obj.is_valid(): # obj.save() ##他裏面的源碼默認是commit=True 會幫你第三張表一起修改了。而在django是可以自己手動指定修改的 mobj = obj.save(commit=False) #要是commit為False的話,他會返回一個model的對象、點擊commit看源碼 mobj.save() ##保存自己表中數據 mobj.save_m2m() ##修改第三張表中的數據,而你要在這二者之間是可以做,一些你想做的事情的 return render(request,"mf.html",locals())
template:
<form action="" method="post"> {% csrf_token %} {{ obj.as_p }} <input type="submit"> </form>
ModelForm中Meta的詳解
# from web import forms from django.forms import Form ##Form要繼承的 from django.forms import ModelForm ##ModelForm繼承 from web import models from django.forms import widgets as ws from django import forms from django.forms import fields class NewsModelForm(ModelForm): email = fields.CharField() ##這個會叫把原來的email字段覆蓋,變成了CharField的屬性驗證 pwd = fields.CharField() ##還能夠增加一個News中model之外的字段,很有用。的 class Meta: model = models.News ##裏面必須要有一個model,因為他是對每個models類做增刪改查的 fields = "__all__" ##指定了類,要需要指定要處理哪幾個字段 __all__是全部字段 #exclude = ["email",] ##排除某個字段 labels = {"name":"名字","title":"標題"} ##顯示字段的label help_texts = {"title":"*"} ##顯示字段的help_texts "*"我們代表為必填 widgets = { "name":ws.Textarea(attrs={"class":"c1"}) ##自定義字段標簽。和加屬性 } error_messages ={ "email":{"required":"必填","invalid":"格式錯誤"} ##自定義錯誤提示 } field_classes = { "name":forms.EmailField ##ModelForm的字段是model中的,name在model是CharField的,而我們可以更改他的驗證以郵箱格式進行驗證 } localized_fields = ("ctime",) ##model中是UTC時間,顯示的時候 按本地時間輸出
動態生成ModelForm表單
def Dynamic_Model_Form(admin_class,form_change=True): class Meta: model = admin_class.model fields = "__all__" ##排除exclude的字段 admin_class.form_change = False ##用戶前端頁面是否生成p標簽的判斷 if form_change: admin_class.form_change = True exclude = admin_class.readonly_fields def __new__(cls,*args,**kwargs): for field_name in cls.base_fields: ##字段都包含在了cls.base_fields中 filed_obj = cls.base_fields[field_name] #添加屬性 filed_obj.widget.attrs.update({‘class‘:‘form-control‘}) ## return ModelForm.__new__(cls) DyModelForm = type("Foo",(ModelForm,),{"Meta":Meta,"__new__":__new__}) return DyModelForm
Model、Form、ModelForm的比較