簡介
Model + Form ==> ModelForm。model和form的結合體,所以有以下功能:
- 驗證
- 數據庫操作
Form回顧
models.py
class UserType(models.Model):
caption = models.CharField(max_length=32)
class UserInfo(models.Model):
username = models.CharField(max_length=32)
email = models.EmailField()
user_type = models.ForeignKey(to='UserType',to_field='id')
forms.py
from django import forms
from django.forms import fields
class UserInfoForm(forms.Form):
# username = models.CharField(max_length=32) <-- models
username = fields.CharField(max_length=32)
# email = models.EmailField() <-- models
email = fields.EmailField()
# user_type = models.ForeignKey(to='UserType',to_field='id') <-- models
user_type = fields.ChoiceField(
choices=models.UserType.objects.values_list('id','caption')
)
# 下面的操作是讓數據在網頁上實時更新。
def __init__(self, *args, **kwargs):
super(UserInfoForm,self).__init__(*args, **kwargs)
self.fields['user_type'].choices = models.UserType.objects.values_list('id','caption')
index.html
<body>
<form action="/index/" method="POST" novalidate="novalidate">
{% csrf_token %}
{{ obj.as_p }}
<input type="submit" value="提交">
</form>
</body>
從上面的小例子能看出,models的字段和forms的字段大部分都是重復的,所以,django給我們提供了一種更為簡潔的ModelFrom
ModelForm的用法
forms.py
class UserInfoModelForm(forms.ModelForm):
class Meta:
model = models.UserInfo # 與models建立了依賴關系
fields = "__all__"
views.py
def index(request):
if request.method == "GET":
obj = UserInfoModelForm()
return render(request,"index.html",{'obj':obj})
elif request.method == "POST":
obj = UserInfoModelForm(request.POST)
print(obj.is_valid()) # 這是方法,別忘記了加括號
print(obj.cleaned_data)
print(obj.errors)
return render(request,"index.html",{'obj':obj})
index.html
<body>
<form action="/index/" method="POST" novalidate="novalidate">
{% csrf_token %}
{{ obj.as_p }}
<input type="submit" value="提交">
</form>
</body>
ModelForm常見參數
自定義字段名(html顯示的字段)
如何定義http上定義的字段呢,自定義寫成中文的?之前的用法是在Form里寫上label。Model Form定義要用verbose_name
指定顯示那些字段
class UserInfo(models.Model):
username = models.CharField(max_length=32, verbose_name='用戶')
email = models.EmailField(verbose_name='郵箱')
user_type = models.ForeignKey(to='UserType',to_field='id', verbose_name='類型')
如果不在model里定義,在modelForm里實現,利用labels
class UserInfoModelForm(forms.ModelForm):
class Meta:
model = models.UserInfo
fields = "__all__"
labels = {
'username':'用戶名',
'email':'郵箱',
}
指定需要展示的字段
fields = "__all__"上面展示所有的,也可以展示指定的列
fields = ['username','email'] # 顯示指定列 exclude = ['username'] # 排除指定列
錯誤信息
error_messages = {
'__all__':{ # 整體錯誤信息
},
'email': {
'required': '郵箱不能為空',
'invalid': '郵箱格式錯誤..',
}
}
給字段添加css屬性
widgets = {
'username': Fwidgets.Textarea(attrs={'class': 'c1'})
}
ModelForm的驗證
跟form一樣,ModleForm里面也有is_valid,cleaned_data,errors,
# Form驗證:
UserInfoForm -> Form -> BaseForm( 包含is_valid等方法)
# ModelForm驗證:
UserInfoModelForm -> ModelForm -> BaseModelForm -> BaseForm
ModelForm對數據庫操作
添加數據
如果數據驗證通過,直接調用save()方法,django會自動往數據庫里添加一條數據(會根據modles里的字段一一對應)
if obj.is_valid():
obj.save() # 創建數據
如果在如下一對多、多對多關系中,如:
class UserType(models.Model):
caption = models.CharField(max_length=32)
class UserGroup(models.Model):
name = models.CharField(max_length=32)
class UserInfo(models.Model):
username = models.CharField(max_length=32)
email = models.EmailField()
user_type = models.ForeignKey(to='UserType',to_field='id')
u2g = models.ManyToManyField(UserGroup)
這樣的話,執行上面的obj.save()會自動在UserInfo表和多對多關系表里都增加數據,灰常灰常方便。
def index(request):
if request.method == "GET":
obj = UserInfoModelForm()
return render(request,'index.html',{'obj': obj})
elif request.method == "POST":
obj = UserInfoModelForm(request.POST)
if obj.is_valid():
obj.save() # 等價以下三句
# instance = obj.save(False)
# instance.save()
# obj.save_m2m()
return render(request,'index.html',{'obj': obj})
修改數據
修改表數據是,記得把instance信息也傳進去,如:mf = UserInfoModelForm(request.POST,instance=user_obj)
不然是新建數據,而不是對某行數據進行修改。
編輯用戶信息,新url方式保留默認數據
urls.py
url(r'^user_list/', views.user_list), url(r'^edit-(\d+)/', views.user_edit),
views.py
def user_list(request):
li = models.UserInfo.objects.all().select_related('user_type') # 這里只能是外鍵,多對多字段也不可以
return render(request,'user_list.html',{'li': li})
def user_edit(request, nid):
# 獲取當前id對象的用戶信息
# 顯示用戶已經存在數據
if request.method == "GET":
user_obj = models.UserInfo.objects.filter(id=nid).first()
mf = UserInfoModelForm(instance=user_obj) # 把默認數據傳遞進去
return render(request,'user_edit.html',{'mf': mf, 'nid': nid})
elif request.method == 'POST':
# 數據修改的信息,給數據庫的哪一行做修改?
user_obj = models.UserInfo.objects.filter(id=nid).first()
mf = UserInfoModelForm(request.POST,instance=user_obj) # 指定給誰做修改
if mf.is_valid():
mf.save()
else:
print(mf.errors.as_json())
return render(request,'user_edit.html',{'mf': mf, 'nid': nid})
user_list.html
<body>
<ul>
{% for row in li %}
<li>{{ row.username }} - {{ row.user_type.caption }} - <a href="/edit-{{ row.id }}/">編輯</a></li>
{% endfor %}
</ul>
</body>
user_edit.html
<body>
<form method="POST" action="/edit-{{ nid }}/">
{% csrf_token %}
{{ mf.as_p }}
<input type="submit" value="提交" />
</form>
</body>
