表单中的Field
和模型中的Field
基本上是一模一样的,而且表单中需要验证的数据,也就是模型中需要保存的。那么这时候可以将模型中的字段和表单中的字段进行绑定。
比如现在有个User
的模型。
from django.db import models
class User(models.Model):
username = models.CharField(max_length=20)
phone = models.CharField(max_length=20)
pwd = models.CharField(max_length=20)
那么在写表单的时候,就不需要把User
模型中所有的字段都一个个重复写一遍了
from django import forms
from .models import User
class RegisterForm(forms.ModelForm):
class Meta:
model = User # 用到的模型名
fields = "__all__" # 使用模型的所有字段
RegisterForm
是继承自forms.ModelForm
,然后在表单中定义了一个Meta
类,在Meta
类中指定了model=User
,以及fields = "__all__"
,这样就可以将Article
模型中所有的字段都复制过来,进行验证。
如果只想针对其中几个字段进行验证,那么可以给fields
指定一个列表,将需要的字段写进去。比如只想验证username
和phone
,那么可以使用以下代码实现:
from django import forms
class RegisterForm(forms.ModelForm):
class Meta:
model = User
fields = ['username','phone']
如果要验证的字段比较多,只是除了少数几个字段不需要验证,那么可以使用exclude
来代替fields
。比如我不想验证pwd
,那么示例代码如下:
class MyForm(forms.ModelForm):
class RegisterForm:
model = User
exclude = ['pwd']
自定义错误消息
使用ModelForm
,因为字段都不是在表单中定义的,而是在模型中定义的,因此一些错误消息无法在字段中定义。那么这时候可以在Meta
类中,定义error_messages
,然后把相应的错误消息写到里面去。示例代码如下:
from django import forms
from .models import User
class RegisterForm(forms.ModelForm):
class Meta:
model = User
# fields = "__all__"
# fields = ["username", "phone"]
exclude = ["pwd"]
error_messages = {
"username": {
'required': '请传入username',
},
"phone": {
'required': '请传入phone',
},
"pwd": {
'required': '请传入pwd',
},
}
save方法
ModelForm
还有save
方法,可以在验证完成后直接调用save
方法,就可以将这个数据保存到数据库中了。示例代码如下:
form = RegisterForm(request.POST)
if form.is_valid():
form.save()
return HttpResponse('succes')
else:
print(form.get_errors())
return HttpResponse('fail')
这个方法必须要在clean
没有问题后才能使用,如果在clean
之前使用,会抛出异常。
在调用save
方法的时候,如果传入一个commit=False
,那么只会生成这个模型的对象,而不会把这个对象真正的插入到数据库中。
比如表单上验证的字段没有包含模型中所有的字段,这时候就可以先创建对象,再根据填充其他字段,把所有字段的值都补充完成后,再保存到数据库中。示例代码如下:
# models.py
from django.db import models
from django.core import validators
# Create your models here.
class User(models.Model):
username = models.CharField(max_length=20)
phone = models.CharField(max_length=20, validators=[validators.RegexValidator(r"1[345678]\d{9}")]) # 对phone进行正则判别
pwd = models.CharField(max_length=20)
# forms.py
from django import forms
from .models import User
class RegisterForm(forms.ModelForm):
pwd1 = forms.CharField(max_length=20, min_length=5) # 密码
pwd_repeat = forms.CharField(max_length=20, min_length=5) # 重新输入的密码
def clean_phone(self): # 对phone这个字段进行数据库验证
phone = self.cleaned_data.get("phone") # 获得表单中phone的值
if User.objects.filter(phone=phone).exists(): # 是否存在
raise forms.ValidationError("已经被注册")
else:
return phone
def clean(self):
ret = super().clean()
pwd1 = ret.get("pwd1") # ==self.cleaned_data.get("pwd1") 获得pwd1字段的值
pwd_repeat = ret.get("pwd_repeat") # 获得pwd2字段的值
if pwd1 != pwd_repeat: # 如果不相同
raise forms.ValidationError("密码不相同")
else:
return ret
class Meta:
model = User
exclude = ["pwd"] # 需要对pwd这个字段进行验证,就先不包括它
error_messages = {
"username": {
'required': '请传入username',
},
"phone": {
'required': '请传入phone',
},
"pwd": {
'required': '请传入pwd',
},
}
# views.py
from django.shortcuts import render, HttpResponse
from django.views.generic import View
# Create your views here.
from .forms import RegisterForm
class RegisterView(View):
def get(self, request):
return HttpResponse("yes")
def post(self, request):
form = RegisterForm(request.POST)
if form.is_valid():
user = form.save(commit=False) # 生成模型对象不直接写入数据库
user.pwd = form.cleaned_data.get("pwd1") # 因为form中没有模型pwd字段的值,只能这样赋值
user.save() # 保存进数据库
return HttpResponse("success")
else:
print(form.errors.get_json_data())
return HttpResponse("failure")