表单中的Field和模型中的Field基本上是一模一样的,而且表单中需要验证的数据,也就是模型中需要保存的。那么这时候可以将模型中的字段和表单中的字段进行绑定。
比如现在有个User的模型。
from django.db import modelsclass 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 formsfrom .models import Userclass 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 formsclass RegisterForm(forms.ModelForm):class Meta:model = Userfields = ['username','phone']
如果要验证的字段比较多,只是除了少数几个字段不需要验证,那么可以使用exclude来代替fields。比如我不想验证pwd,那么示例代码如下:
class MyForm(forms.ModelForm):class RegisterForm:model = Userexclude = ['pwd']
自定义错误消息
使用ModelForm,因为字段都不是在表单中定义的,而是在模型中定义的,因此一些错误消息无法在字段中定义。那么这时候可以在Meta类中,定义error_messages,然后把相应的错误消息写到里面去。示例代码如下:
from django import formsfrom .models import Userclass 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.pyfrom django.db import modelsfrom 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.pyfrom django import formsfrom .models import Userclass 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 phonedef 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 retclass Meta:model = Userexclude = ["pwd"] # 需要对pwd这个字段进行验证,就先不包括它error_messages = {"username": {'required': '请传入username',},"phone": {'required': '请传入phone',},"pwd": {'required': '请传入pwd',},}
# views.pyfrom django.shortcuts import render, HttpResponsefrom django.views.generic import View# Create your views here.from .forms import RegisterFormclass 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")
