django ModelForm
什麽是ModelForm
Django中Model負責操作數據庫,並且具有簡單的數據庫驗證功能;Form用於用戶請求的驗證,具有強悍的數據庫驗證功能;ModelForm是將二者合二為一,即可用於數據庫操作(部分),也可用於用戶請求的驗證(部分)!
其實Django Admin就是利用ModelForm的功能實現的。
Form組件和ModelForm的區別
ModelForm是Django Model.py和Form組件的結合體,可以簡單/快速使用 Form驗證和數據庫操作功能,但不如Form組件靈活,如果在使用Django做web開發過程中驗證的數據和數據庫字段相關(可以對表進行增、刪、改操,註意 Many to many字段,也可以級聯操作第3張關系表;),建議優先使用ModelForm,用起來更方便些,但是在使用ModelForm的時候慎用fields=‘__all__‘,獲取數據庫所有字段勢必造成性能損耗;
ModelForm應用場景
我們來假設這樣一個場景,假如,我們有一個類需要保存org的一些信息如下面這些字段。這個類我們叫做ChangOrgModel
course_num = models.IntegerField(default=0, verbose_name=u‘課程數‘) students_num = models.IntegerField(default=0, verbose_name=u‘學習人數‘) address = models.CharField(max_length=200, verbose_name=u‘地址‘)
如果我們使用form我們需要怎麽做呢。我們大概需要這樣做。
class OrgModelForm(forms.Form): course_num = forms.IntegerField() students_num = forms.IntegerField() address = forms.CharField(max_length=200)
我們不難發現,我們的Form定義跟Model的定義基本沒什麽區別,應該加max_length的時候還是需要加,我們相當於是重寫了一遍,其次,這裏只有三個,並沒有感覺,當有7、8甚至更多的時候,這樣重復操作就很讓人受不了了。所以這裏我們可以使用ModelForm。
定義ModelForm類
from django import forms from app01 import models class UserModelForm(forms.ModelForm): class Meta: model = models.User #關聯的model類 fields = "__all__" #或(‘name‘,‘email‘,‘user_type‘) #驗證哪些字段,"__all__"表示所有字段 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 = () #本地化,根據settings中TIME_ZONE設置的不同時區顯示時間
ModelForm驗證執行的過程
Form所有的鉤子ModelForm都有。
is_valid()-->self.errors-->full_clean()-->self._clean_fields() --> clean_字段名(自定義方法) self._clean_form() --> clean(self) self._post_clean() (整體錯誤) clean_字段名(自定義方法)
舉例
新建一個項目untitled1,註意: django版本為1.11
修改models.py
from django.db import models class Depart(models.Model): # 部門 caption = models.CharField(verbose_name=‘部門‘,max_length=32) def __str__(self): return self.caption class Role(models.Model): # 角色 title = models.CharField(verbose_name=‘角色名‘,max_length=32) def __str__(self): return self.title class User(models.Model): # 用戶 name = models.CharField(verbose_name=‘姓名‘,max_length=32) depart = models.ForeignKey(verbose_name=‘部門‘,to=‘Depart‘,on_delete=models.CASCADE) gender_choices = ( (1,‘男‘), (2,‘女‘), ) gender = models.IntegerField(verbose_name=‘性別‘,choices=gender_choices,default=1) roles = models.ManyToManyField(verbose_name=‘角色‘,to=‘Role‘)
執行命令,生成表
python manage.py makemigrations
python manage.py migrate
修改admin.py,註冊表
from django.contrib import admin from app01 import models # Register your models here. admin.site.register(models.Depart) admin.site.register(models.Role) admin.site.register(models.User)
創建超級用戶
登錄admin後臺,錄入數據。這樣做的目的是為了渲染頁面時,不會出現空頁面!
錄入基本數據
修改urls.py,增加路由
from app01 import views urlpatterns = [ url(r‘^admin/‘, admin.site.urls), url(r‘^user/list/$‘, views.user_list), ]
修改views.py,增加視圖
from django.shortcuts import render from app01 import models # Create your views here. def user_list(request): user_queryset = models.User.objects.all() return render(request,‘user_list.html‘,{‘user_queryset‘:user_queryset})
在templates目錄下,創建文件user_list.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="container"> <a href="/user/add/" class="btn btn-primary">添加</a> <table class="table table-bordered"> <thead> <tr> <th>名稱</th> <th>性別</th> <th>部門</th> <th>角色</th> <th>操作</th> </tr> </thead> <tbody> {% for row in user_queryset %} <tr> <td>{{ row.name }}</td> <td>{{ row.get_gender_display }}</td> <td>{{ row.depart.caption }}</td> <td> {% for node in row.roles.all %} <span>{{ node.title }}</span> {% endfor %} </td> <td> <a href="/user/edit/{{ row.id }}/">編輯</a> </td> </tr> {% endfor %} </tbody> </table> </div> </body> </html>View Code
訪問頁面:http://127.0.0.1:8000/user/list/
默認是空的。需要寫添加頁面
添加頁面,怎麽寫呢?寫4個input框?假如有10個表呢?累成狗!
使用ModelForm,根據models.py定義的字段,自動生成input框!
添加功能
修改urls.py,增加路由
urlpatterns = [ url(r‘^admin/‘, admin.site.urls), url(r‘^user/list/$‘, views.user_list), url(r‘^user/add/$‘, views.user_add), ]View Code
修改views.py,增加添加頁面,使用ModelForm
需要導入forms組件
from django.shortcuts import render,redirect from app01 import models from django import forms # Create your views here. def user_list(request): user_queryset = models.User.objects.all() return render(request,‘user_list.html‘,{‘user_queryset‘:user_queryset}) class UserForm(forms.ModelForm): # 類名最好是表名+Form class Meta: model = models.User # user表 fields = ‘__all__‘ # 所有字段 # fields = [‘name‘,‘depart‘] widgets = { # 定義name字段的輸入框為text ‘name‘:forms.TextInput(attrs={‘class‘:‘form-control‘}), # 定義depart字段的輸入框為Select ‘depart‘:forms.Select(attrs={‘class‘:‘form-control‘}), ‘gender‘:forms.Select(attrs={‘class‘:‘form-control‘}), # 定義roles字段的輸入框為多選框 ‘roles‘:forms.SelectMultiple(attrs={‘class‘:‘form-control‘}), } # 錯誤信息 error_messages = { # name字段的錯誤信息 ‘name‘:{ # 英文的required轉為中文提示 ‘required‘:‘用戶名不能為空‘ } } def user_add(request): if request.method == "GET": form = UserForm() # 實例化一個空的ModelForm對象 else: form = UserForm(request.POST) # 接收POST請求數據 if form.is_valid(): # 進行驗證 print(‘通過驗證‘) form.save() # 將驗證通過的數據插入到數據庫中 return redirect(‘/user/list/‘) # 重定向頁面 return render(request,‘user_add.html‘,{‘form‘:form})View Code
在templates目錄下,創建文件user_add.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="container"> <h1>添加用戶</h1> <form method="post" class="form-horizontal" novalidate> {% csrf_token %} {#for循環form對象#} {% for field in form %} <div class="form-group"> {#顯示字段名#} <label class="col-sm-2 control-label">{{ field.label }} </label> <div class="col-sm-10"> {#顯示字段的輸入框以及錯誤信息,0表示取第一個錯誤#} {{ field }} {{ field.errors.0 }} </div> </div> {% endfor %} <input type="submit" value="提交"> </form> </div> </body> </html>View Code
刷新頁面,點擊添加,效果如下:
直接提交空表單,會有錯誤提示
添加一個正常數據
添加成功後,頁面會自動跳轉
修改功能
修改urls.py , 增加路由
urlpatterns = [ url(r‘^admin/‘, admin.site.urls), url(r‘^user/list/$‘, views.user_list), url(r‘^user/add/$‘, views.user_add), url(r‘^user/edit/(?P<uid>\d+)/$‘, views.user_edit), ]
修改views.py,增加視圖
from django.shortcuts import render,redirect from app01 import models from django import forms # Create your views here. def user_list(request): user_queryset = models.User.objects.all() return render(request,‘user_list.html‘,{‘user_queryset‘:user_queryset}) class UserForm(forms.ModelForm): # 類名最好是表名+Form class Meta: model = models.User # user表 fields = ‘__all__‘ # 所有字段 # fields = [‘name‘,‘depart‘] widgets = { # 定義name字段的輸入框為text ‘name‘:forms.TextInput(attrs={‘class‘:‘form-control‘}), # 定義depart字段的輸入框為Select ‘depart‘:forms.Select(attrs={‘class‘:‘form-control‘}), ‘gender‘:forms.Select(attrs={‘class‘:‘form-control‘}), # 定義roles字段的輸入框為多選框 ‘roles‘:forms.SelectMultiple(attrs={‘class‘:‘form-control‘}), } # 錯誤信息 error_messages = { # name字段的錯誤信息 ‘name‘:{ # 英文的required轉為中文提示 ‘required‘:‘用戶名不能為空‘ } } def user_add(request): if request.method == "GET": form = UserForm() # 實例化一個空的ModelForm對象 else: form = UserForm(request.POST) # 接收POST請求數據 if form.is_valid(): # 進行驗證 print(‘通過驗證‘) form.save() # 將驗證通過的數據插入到數據庫中 return redirect(‘/user/list/‘) # 重定向頁面 return render(request,‘user_add.html‘,{‘form‘:form}) def user_edit(request,uid): # 查詢指定id的數據 obj = models.User.objects.filter(id=uid).first() if request.method ==‘GET‘: # 賦值instance可以使form表單是可以接受對象的數據 form = UserForm(instance=obj) return render(request,‘user_edit.html‘,{‘form‘:form}) else: # instance的參數,如果存在那麽save()方法會更新這個實例,否則會創建一個新的實例 # 由於這裏是更新,如果不指定instance。那麽它會新增一條數據 # 我們這裏不需要新增,必須要指定instance參數 form = UserForm(data=request.POST,instance=obj) if form.is_valid(): form.save() # 更新一條數據 return redirect(‘/user/list/‘) # 重定向 else: return render(request, ‘user_edit.html‘, {‘form‘: form})View Code
在templates目錄下,創建文件user_edit.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="container"> <h1>編輯用戶</h1> <form method="post" novalidate> {% csrf_token %} {% for field in form %} <div>{{ field.label }}{{ field }} {{ field.errors.0 }}</div> {% endfor %} <input type="submit" value="提交"> </form> </div> </body> </html>View Code
刷新頁面,點擊第一條數據後面的編輯,效果如下:
上面會自動渲染數據,那麽問題來了,它是如何渲染頁面的?
看views中的一段代碼
if request.method ==‘GET‘: # 賦值instance可以使form表單是可以接受對象的數據 form = UserForm(instance=obj) return render(request,‘user_edit.html‘,{‘form‘:form})
這裏的obj就是,表裏面的一條數據,也就是一個對象。那麽執行render時,會渲染這個變量。
看前端頁面代碼
<div>{{ field.label }}{{ field }} {{ field.errors.0 }}</div>
這裏的field,就是字段對象。註意:這個對象是有值的,forms組件會渲染它!
修改一下數據
點擊提交,它會自動跳轉
數據就更改了!
刪除功能
添加路由
修改user_list.html, 增加刪除按鈕
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="container"> <a href="/user/add/" class="btn btn-primary">添加</a> <table class="table table-bordered"> <thead> <tr> <th>名稱</th> <th>性別</th> <th>部門</th> <th>角色</th> <th>操作</th> </tr> </thead> <tbody> {% for row in user_queryset %} <tr> <td>{{ row.name }}</td> <td>{{ row.get_gender_display }}</td> <td>{{ row.depart.caption }}</td> <td> {% for node in row.roles.all %} <span>{{ node.title }}</span> {% endfor %} </td> <td> <a href="/user/edit/{{ row.id }}/">編輯</a> <a href="/user/del/{{ row.id }}/">刪除</a> </td> </tr> {% endfor %} </tbody> </table> </div> </body> </html>View Code
刷新頁面,點擊刪除
參考博客
https://www.cnblogs.com/xiao987334176/p/9524510.html
django ModelForm