表单中的Field和模型中的Field基本上是一模一样的,而且表单中需要验证的数据,也就是模型中需要保存的。那么这时候可以将模型中的字段和表单中的字段进行绑定。
比如现在有个User的模型。

  1. from django.db import models
  2. class User(models.Model):
  3. username = models.CharField(max_length=20)
  4. phone = models.CharField(max_length=20)
  5. pwd = models.CharField(max_length=20)

那么在写表单的时候,就不需要把User模型中所有的字段都一个个重复写一遍了

  1. from django import forms
  2. from .models import User
  3. class RegisterForm(forms.ModelForm):
  4. class Meta:
  5. model = User # 用到的模型名
  6. fields = "__all__" # 使用模型的所有字段

RegisterForm是继承自forms.ModelForm,然后在表单中定义了一个Meta类,在Meta类中指定了model=User,以及fields = "__all__",这样就可以将Article模型中所有的字段都复制过来,进行验证。
如果只想针对其中几个字段进行验证,那么可以给fields指定一个列表,将需要的字段写进去。比如只想验证usernamephone,那么可以使用以下代码实现:

  1. from django import forms
  2. class RegisterForm(forms.ModelForm):
  3. class Meta:
  4. model = User
  5. fields = ['username','phone']

如果要验证的字段比较多,只是除了少数几个字段不需要验证,那么可以使用exclude来代替fields。比如我不想验证pwd,那么示例代码如下:

  1. class MyForm(forms.ModelForm):
  2. class RegisterForm:
  3. model = User
  4. exclude = ['pwd']

自定义错误消息

使用ModelForm,因为字段都不是在表单中定义的,而是在模型中定义的,因此一些错误消息无法在字段中定义。那么这时候可以在Meta类中,定义error_messages,然后把相应的错误消息写到里面去。示例代码如下:

  1. from django import forms
  2. from .models import User
  3. class RegisterForm(forms.ModelForm):
  4. class Meta:
  5. model = User
  6. # fields = "__all__"
  7. # fields = ["username", "phone"]
  8. exclude = ["pwd"]
  9. error_messages = {
  10. "username": {
  11. 'required': '请传入username',
  12. },
  13. "phone": {
  14. 'required': '请传入phone',
  15. },
  16. "pwd": {
  17. 'required': '请传入pwd',
  18. },
  19. }

save方法

ModelForm还有save方法,可以在验证完成后直接调用save方法,就可以将这个数据保存到数据库中了。示例代码如下:

  1. form = RegisterForm(request.POST)
  2. if form.is_valid():
  3. form.save()
  4. return HttpResponse('succes')
  5. else:
  6. print(form.get_errors())
  7. return HttpResponse('fail')

这个方法必须要在clean没有问题后才能使用,如果在clean之前使用,会抛出异常。
在调用save方法的时候,如果传入一个commit=False,那么只会生成这个模型的对象,而不会把这个对象真正的插入到数据库中
比如表单上验证的字段没有包含模型中所有的字段,这时候就可以先创建对象,再根据填充其他字段,把所有字段的值都补充完成后,再保存到数据库中。示例代码如下:

  1. # models.py
  2. from django.db import models
  3. from django.core import validators
  4. # Create your models here.
  5. class User(models.Model):
  6. username = models.CharField(max_length=20)
  7. phone = models.CharField(max_length=20, validators=[validators.RegexValidator(r"1[345678]\d{9}")]) # 对phone进行正则判别
  8. pwd = models.CharField(max_length=20)
  1. # forms.py
  2. from django import forms
  3. from .models import User
  4. class RegisterForm(forms.ModelForm):
  5. pwd1 = forms.CharField(max_length=20, min_length=5) # 密码
  6. pwd_repeat = forms.CharField(max_length=20, min_length=5) # 重新输入的密码
  7. def clean_phone(self): # 对phone这个字段进行数据库验证
  8. phone = self.cleaned_data.get("phone") # 获得表单中phone的值
  9. if User.objects.filter(phone=phone).exists(): # 是否存在
  10. raise forms.ValidationError("已经被注册")
  11. else:
  12. return phone
  13. def clean(self):
  14. ret = super().clean()
  15. pwd1 = ret.get("pwd1") # ==self.cleaned_data.get("pwd1") 获得pwd1字段的值
  16. pwd_repeat = ret.get("pwd_repeat") # 获得pwd2字段的值
  17. if pwd1 != pwd_repeat: # 如果不相同
  18. raise forms.ValidationError("密码不相同")
  19. else:
  20. return ret
  21. class Meta:
  22. model = User
  23. exclude = ["pwd"] # 需要对pwd这个字段进行验证,就先不包括它
  24. error_messages = {
  25. "username": {
  26. 'required': '请传入username',
  27. },
  28. "phone": {
  29. 'required': '请传入phone',
  30. },
  31. "pwd": {
  32. 'required': '请传入pwd',
  33. },
  34. }
  1. # views.py
  2. from django.shortcuts import render, HttpResponse
  3. from django.views.generic import View
  4. # Create your views here.
  5. from .forms import RegisterForm
  6. class RegisterView(View):
  7. def get(self, request):
  8. return HttpResponse("yes")
  9. def post(self, request):
  10. form = RegisterForm(request.POST)
  11. if form.is_valid():
  12. user = form.save(commit=False) # 生成模型对象不直接写入数据库
  13. user.pwd = form.cleaned_data.get("pwd1") # 因为form中没有模型pwd字段的值,只能这样赋值
  14. user.save() # 保存进数据库
  15. return HttpResponse("success")
  16. else:
  17. print(form.errors.get_json_data())
  18. return HttpResponse("failure")