Django ModelForm表單驗證
ModelForm
在使用Model和Form時,都需要對欄位進行定義並指定型別,通過ModelForm則可以省去From中欄位的定義
應用場景:定製model admin 的時候可以使用。適用於小業務架構。
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={...})
views.py
class UserInfoModelForm(forms.ModelForm): class Meta(object): model = models.UserInfo fields = '__all__' # 請求處理 class ModelFormTest(View): def get(self, request): # ModelForm 建立物件 verify_obj = UserInfoModelForm() return render(request, 'modelForm.html', {'verify_obj': verify_obj})
models.py
class UserType(models.Model): caption = models.CharField(max_length=32) class UserInfo(models.Model): username = models.CharField(verbose_name='使用者名稱', max_length=32) email = models.EmailField() user_type = models.ForeignKey(to=UserType, to_field='id', on_delete=models.SET_NULL,null=True)
注:verbose_name 為django admin管理資料 的時候顯示 的欄位。在模板中渲染時,呼叫modelForm物件例項也可以顯示對應的中文
{{ verify_obj.as_p }}
{{ verify_obj.as_ul }}
{{ verify_obj.as_table }}
modelForm.html
<form action="/modelformtest/" method="post"> {% csrf_token %} {{ verify_obj.as_p }} <input type="submit" value="提交"> </form>
訪問效果
-------------------------------------------------------------------------------------------------------------
只展示指定列fields =
class UserInfoModelForm(forms.ModelForm): class Meta(object): model = models.UserInfo # fields = '__all__' fields = ['username', ]
排除指定列 :exclude = ['xxx',...]
class UserInfoModelForm(forms.ModelForm): class Meta(object): model = models.UserInfo # fields = '__all__' # fields = ['username', ] exclude = ['username']
labels 效果等於models.py裡面定義資料表字段時的 verbose_name='xxx'
為對輸入欄位自定義提示語
views.py
class UserInfoModelForm(forms.ModelForm): class Meta(object): model = models.UserInfo # 從哪個models 資料表裡面獲取欄位 fields = '__all__' # 展示哪些欄位 labels = { # 生成html標籤的對應input標籤前面的提示 'username': 'lables 使用者名稱', 'email': '郵箱', 'user_type': '使用者型別' } class ModelFormTest(View): def get(self, request): # ModelForm 建立物件 verify_obj = UserInfoModelForm() return render(request, 'modelForm.html', {'verify_obj': verify_obj})
modelForm.html
<form action="/modelformtest/" method="post"> {% csrf_token %} {{ verify_obj.as_p }} <input type="submit" value="提交"> </form>
------------------------------------------------------------------------
help_texts=None, # 幫助提示資訊
views.py
class UserInfoModelForm(forms.ModelForm): class Meta(object): model = models.UserInfo # 從哪個models 資料表裡面獲取欄位 fields = '__all__' # 展示哪些欄位 help_texts = { # 提示資訊 'username': '使用者名稱哦', 'email': '郵箱啊' } class ModelFormTest(View): def get(self, request): # ModelForm 建立物件 verify_obj = UserInfoModelForm() return render(request, 'modelForm.html', {'verify_obj': verify_obj})
html
{{ verify_obj.as_p }}
--------------------------------------------------------------------
widgets=None, # 自定義標籤型別外掛
wiews.py
class UserInfoModelForm(forms.ModelForm): class Meta(object): model = models.UserInfo # 從哪個models 資料表裡面獲取欄位 fields = '__all__' # 展示哪些欄位 widgets = { 'username': forms_widgets.Textarea(attrs={'class': 'test-class'}) } class ModelFormTest(View): def get(self, request): # ModelForm 建立物件 verify_obj = UserInfoModelForm() return render(request, 'modelForm.html', {'verify_obj': verify_obj})
html
<form action="/modelformtest/" method="post"> {% csrf_token %} {{ verify_obj.as_p }} <input type="submit" value="提交"> </form>
--------------------------------------------------------------------------------------------
error_messages = {'欄位名': {'錯誤型別': '錯誤提示', ... }}
class UserInfoModelForm(forms.ModelForm):
class Meta(object):
model = models.UserInfo # 從哪個models 資料表裡面獲取欄位
fields = '__all__' # 展示哪些欄位
error_messages = {
'email': {
'required': '必填',
'invalid': '郵箱格式錯誤'
},
'username': {
'max_length': '太長了',
'min_length': '太短了',
}
}
class ModelFormTest(View):
def get(self, request):
# ModelForm 建立物件
verify_obj = UserInfoModelForm()
return render(request, 'modelForm.html', {'verify_obj': verify_obj})
def post(self, request):
# 獲取所有資料
# 每條資料請求的驗證
# 成功顯示正確資訊
# 失敗,給出錯誤提示
# 驗證時將request.POST 傳遞給驗證類,例項化驗證物件
# verify_obj = MyFm(request.POST)
verify_obj = UserInfoModelForm(request.POST)
verify_result = verify_obj.is_valid() # 驗證是否通過,返回True/False
if not verify_result:
return render(request, 'modelForm.html', {'verify_obj': verify_obj})
# 整體錯誤資訊使用 '__all__' 代表所有欄位
error_messages = {
'__all__': {
'required': '必填',
'invalid': '格式錯誤'
},
}
生成html瀏覽器檢視效果
-------------------------------------------
field_classes 更改原有欄位型別
views.py
class UserInfoModelForm(forms.ModelForm): class Meta(object): model = models.UserInfo # 從哪個models 資料表裡面獲取欄位 fields = '__all__' # 展示哪些欄位 from django.forms import fields as form_fields field_classes = { 'email':form_fields.URLField }
-------------------------------------------------------------------------------------------------
localized_fields=('birth_date',) # 將資料本地化顯示,如:根據不同時區顯示資料
前提:
需要在settings.py中設定好本地的時區
# setting中的配置 TIME_ZONE = 'Asia/Shanghai' # 時區 USE_TZ = True # 啟用本地時區
views.py
localized_fields=('birth_date',) # 本地化,如:根據不同時區顯示資料 # 如資料庫中存的 2016-12-27 04:10:57 # 則前端顯示:2016-12-27 12:10:57
ModelForm 的資料庫儲存方式
驗證有效,直接使用驗證例項.save() 儲存到資料庫
views.py
class ModelFormTest(View): def get(self, request): # ModelForm 建立物件 verify_obj = UserInfoModelForm() return render(request, 'modelForm.html', {'verify_obj': verify_obj}) def post(self, request): # 獲取所有資料 # 每條資料請求的驗證 # 成功顯示正確資訊 # 失敗,給出錯誤提示 # 驗證時將request.POST 傳遞給驗證類,例項化驗證物件 # verify_obj = MyFm(request.POST) verify_obj = UserInfoModelForm(request.POST) if verify_obj.is_valid(): # 預設儲存多對多 :第三張表的資料 verify_obj.save() # 不做任何操作,內部定義 save_m2m(用於儲存多對多) #verify_obj.save(commit=False) #verify_obj.save() # 儲存單張表資訊 #verify_obj.save_m2m() # 儲存關聯多對多 第三張表的資訊
models.py
資料表結構UserInfo UserType UserGroup
UserInfo ---> UserType 一對多
UserInfo<----> UserGroup 多對多
class UserType(models.Model): caption = models.CharField(max_length=32) def __str__(self): return self.caption class UserGroup(models.Model): name = models.CharField(max_length=32) class UserInfo(models.Model): username = models.CharField(verbose_name='使用者名稱', max_length=32) email = models.EmailField() user_type = models.ForeignKey(to=UserType, to_field='id', on_delete=models.SET_NULL,null=True) u_in_g = models.ManyToManyField(UserGroup)
-----------------------------------------------------------------------
應用案例:使用者列表 檢視/編輯使用者資訊,儲存到資料庫
models.py
UserInfo 表 user_type欄位外來鍵UserType id欄位
UserInfo 表u_in_g欄位外來鍵 多對多 UserGroup表id欄位
from django.db import models # Create your models here. class UserType(models.Model): caption = models.CharField(max_length=32) def __str__(self): return self.caption class UserGroup(models.Model): name = models.CharField(max_length=32) def __str__(self): return self.name class UserInfo(models.Model): username = models.CharField(verbose_name='使用者名稱', max_length=32) email = models.EmailField() user_type = models.ForeignKey(to=UserType, to_field='id', on_delete=models.SET_NULL,null=True) u_in_g = models.ManyToManyField(UserGroup)
查已儲存的資料資訊展示給前端
ModelForm 指定instance 資料物件(自定義的資料表 具體的查詢結果物件),可以顯示給前端
例如:user_html_obj = UserInfoModelForm(instance=user_data)
更新資料庫中的資訊
例如:
user = models.UserInfo.objects.filter(id=uid).first()
mf_obj = UserInfoModelForm(request.POST, instance=user)
mf_obj.save()
驗證post請求的資料有效。更新到指定的查詢結果中去,如果不指定instance 則為新增資料操作
views.py
class UserList(View): def get(self, request): users = models.UserInfo.objects.all().select_related('user_type') return render(request, 'modelForm_user_lisst.html' , {'users': users}) class UserEdit(View): def get(self, request, uid): user_data = models.UserInfo.objects.filter(id=uid).first() print('資料查詢:', type(user_data)) # 將資料庫查詢出來的資料物件 user_html_obj = UserInfoModelForm(instance=user_data) return render(request, 'ModelForm_user_edit.html', {'user_html_obj': user_html_obj, 'uid': uid}) pass def post(self, request,uid): user = models.UserInfo.objects.filter(id=uid).first() mf_obj = UserInfoModelForm(request.POST, instance=user) # 更新的資料符合要求,儲存到資料庫 if mf_obj.is_valid(): mf_obj.save() else: print(mf_obj.errors.as_json) return render(request, 'ModelForm_user_edit.html', {'user_html_obj': mf_obj, 'uid': uid})
modelForm的鉤子
1、在提交驗證的資料前對資料進行修改
定義 def clean_欄位名():函式 對self.cleaned_data中獲取到的欄位進行修改
class UserInfoModelForm(forms.ModelForm): class Meta(object): #..................... def clean_username(self): old_username = self.cleaned_data.get('username') return old_username + '呵呵'