Bootstrap

Django Form&ModelForm

一、Form组件

所有框架一般都有自己的表单验证组件,没有也会使用第三方的组件进行验证。组件一般都有一下功能:

  • 表单验证
  • 自动生成HTML标签
  • 数据初始化(新建按钮、编辑按钮)
  • 报错后,保留原有数据,不让用户全部重新输入。

1.1.生成HTML标签

class RegisterForm(forms.Form):
    name = forms.CharField(
        # required=True 代表必填项,不填则报错
        required = True,
        # initial 代表初始化值
        initial = 'SZR',
        # widget 则是使用表单生成的HTML标签
        widget = forms.TextInput
    )
   
def register(request):
	form = RegisterForm()
	return render(request,'register_form.html',{'form':form})
 
# register_form.html
{{form.name}}

运行后,得到结果:
在这里插入图片描述
检查源码,默认生成了标签。

<input type="text" name="name" value="SZR" required id="id_name">

默认会生成一个id_ + 字段名
也可以自己设置id

class RegisterForm(forms.Form):
    name = forms.CharField(
		...
        widget = forms.TextInput(attrs={'id':xx1})
    )

1.2 表单验证:

触发验证的代码form.is_valid()

def register(request):
    if request.method == 'GET':
        form = RegisterForm()
        return render(request, 'register_form.html', {'form': form})
    # 请求为 post 方法
    form = RegisterForm(data=request.POST)
    if form.is_valid():
        print(form.cleaned_data)
        return HttpResponse('success')
    else:
        print(form.errors)
        return HttpResponse('fail')
mobile = forms.CharField(
    required=True,
    validators=[RegexValidator(r'^\d{11}$', "手机号格式错误")],
    widget=forms.TextInput
)
  • required =True
    当提交为空时,后台就会报错。
    ps:如果要验证这个点,在html中,需要去掉浏览器的验证
    需要加入<form action="post" novalidate>

  • validators=[RegexValidator(r’^\d{11}$', “手机号格式错误”)]
    这个是正则表达是验证,规定写法,必须是RegexValidator
    需要导入模块from django.core.validators import RegexValidator

  • 钩子方法
    如果是只用正则去校验,可能很多业务场景无法校验,例如,注册手机号不能重复,这样则无法校验,可以使用提供的钩子方法。固定写法
    clean_ + 定义的字段名
    如:

class RegisterForm(forms.Form):
	mobile = ....
	
    def clean_mobile(self):
    	# 查询数据库,手机号是否存在
    	....
        raise ValidationError('手机号已存在')

定义了才会执行,没定义就不执行
ps:系统自带错误全是英文,如果需要显示为中文,则可以更改settings配置

# LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = 'zh-hans'

1.3 数据初始化

  • 在定义字段的时候初始化initial
    例如
class RegisterForm(forms.Form):
    name = forms.CharField(
        required = True,
        initial = 'SZR',
        widget = forms.TextInput
    )
  • 在实例化form的时候初始化
form = RegisterForm(initial={"name": "SZR", "moblie": "123"})

1.2错误信息展示

在这里插入图片描述
发生错误,将页面重新展示,错误信息会被展示,由于错误信息是一个列表,一般展示第0个就行

1.3 循环展示所有字段

当定义的字段较多,一个个去写,就不大方便。此时就可以使用循环展示所有对象。

{% for filed in form %}
    <p>{{ filed.label }}{{ filed }}{{filed.errors.0}}</p>
{% endfor %}

label则是在定义字段时,取的名字,可以展示在输入框前方

1.4关于样式

手动添加样式

widget添加attrs

class RegisterForm(forms.Form):
    v1 = forms.CharField(
        label="手机号",
        required=True,
        # initial="12345678909",
        validators=[RegexValidator(r'^1[357]\d{7}$', "手机号格式错误"), ],
        widget=forms.TextInput(attrs={"class":"form-control"}) # <input type="text" class="form-control"/>
    )

2.自动操作

找到每个字段中的widget插件,再找到插件中的attrs属性,给每个attrs赋值**{“class”:“form-control”}**

class RegisterForm(forms.Form):
    v1 = forms.CharField(...,widget=forms.TextInput)
    v2 = forms.CharField(...,widget=forms.TextInput(attrs={"v1":"123"}))
    
    def __init__(self,*args,**kwargs):
        super().__init__(self,*args,**kwargs)
        for name,field in self.fields.items():
            if name == "v1":
                continue 
            if field.widget.attrs:
                field.widget.attrs.update({"class":"form-control"})
            else:
            	field.widget.attrs = {"class":"form-control"}

3.写一个通用父类,再继承该父类,可以实现复用

class BootStrapForm(forms.Form):
    def __init__(self, *args, **kwargs):
        # 不是找父类
        # 根据类的mro(继承关系),去找上个类
        # super().__init__(*args, **kwargs)
        for name, field in self.fields.items():
            field.widget.attrs = {"class": "form-control"}

class LoginForm(BootStrapForm):
    user = forms.CharField(label="用户名", widget=forms.TextInput)
    pwd = forms.CharField(label="密码", widget=forms.TextInput)

def login(request):
    form = LoginForm()
    return render(request, "login.html", {"form": form})

二、ModelForm

ModelForm需要结合models.py 创建的表来使用

2.1 使用Form组件的操作

  • 创建Form类 + 定义字段

    class LoginForm(forms.Form):
        user = forms.CharField(label="用户名", widget=forms.TextInput)
        pwd = forms.CharField(label="密码", widget=forms.TextInput)
    
  • 视图

    def login(request):
        if request.method == "GET":
            form = LoginForm()
            return render(request, "login.html", {"form": form})
        form = LoginForm(data=request.POST)
        if not form.is_valid():
            # 校验失败
            return render(request, "login.html", {"form": form})
        print(form.cleaned_data)
        # ...
        return HttpRespon("OK")
    
  • 前端

    <form>
        {% for field in form %}
        <p>{{ field.label }} {{ field }} {{ field.errors.0 }}</p>
        {% endfor %}
    </form>
    

2.2 使用ModelForm

  • models.py

    class UserInfo(models.Model):
        name = models.CharField(verbose_name="用户名", max_length=32)
        age = models.IntegerField(verbose_name="年龄")
        email = models.CharField(verbose_name="邮箱", max_length=128)
    
  • 创建ModelForm
    可以增加想要的字段,也可以选择需要展示的字段

    class LoginForm(forms.ModelForm):
        mobile = forms.CharFiled(label="手机号")
    	class Meta:
            model = models.UserInfo
            fileds = ["name","age", "mobile"]
    
  • 视图使用

    def login(request):
        form = LoginModelForm()
        return render(request, "login.html", {"form": form})
    
  • 页面

    <form>
        {% for field in form %}
        <p>{{ field.label }} {{ field }} {{ field.errors.0 }}</p>
        {% endfor %}
    </form>
    

2.3 ModelForm的便捷之处

2.3.1 初始化数据

  • 使用Form初始化数据,需要挨个挨个去赋值
class LoginForm(BootStrapForm, forms.Form):
    user = forms.CharField(label="用户名", widget=forms.TextInput)
    pwd = forms.CharField(label="密码", widget=forms.TextInput)
def login(request):
    form = LoginForm(initial={"user": "SZR", "pwd": "123"})
    return render(request, "login.html", {"form": form})
  • 使用ModelForm
class LoginModelForm(forms.ModelForm):
    mobile = forms.CharField(label="手机号", widget=forms.TextInput)

    class Meta:
        model = models.UserInfo
        fields = ["name", "age", "mobile"]
        widgets = {
            "age": forms.TextInput,
        }
        labels = {
            "age": "x2",
        }
	# 定义钩子方法
    def clean_name(self):
        value = self.cleaned_data['name']
        # raise ValidationError("....")
        return value
def login(request):
    user_object = models.UserInfo.objects.filter(id=1).first()
    form = LoginModelForm(instance=user_object, initial={"mobile": "12345678909"})
    return render(request, "login.html", {"form": form})

ModelForm可以直接从数据库读取展示。所以比较方便

2.3.2 数据保存

  • Form组件
  def login(request):
      if request.method == "GET":
      	form = LoginForm(initial={"user": "SZR", "pwd": "123"})
      	return render(request, "login.html", {"form": form})
      form = LoginForm(data=request.POST)
      if not form.is_valid():
          return render(request, "login.html", {"form": form})
      # form.cleaned_data
      # 手动读取字典,保存至数据库
      models.UserInfo.objects.create(name=form.cleaned_data['name'], pwd=form.cleaned_data['pwd'])
      return HttpResponse("成功")
  • ModelForm组件
form.save() # 自动将数据新增到数据库
  def login(request):
      if request.method == "GET":
      	form = LoginForm()
      	return render(request, "login.html", {"form": form})
      
      form = LoginForm(data=request.POST)
      if not form.is_valid():
          return render(request, "login.html", {"form": form})
      
      form.save() # 自动将数据新增到数据库
      return HttpResponse("成功")

2.3.3 更新数据

  • Form组件
  def login(request):
      if request.method == "GET":
      	form = LoginForm(initial={"user": "SZR", "pwd": "123"})
      	return render(request, "login.html", {"form": form})
      form = LoginForm(data=request.POST)
      if not form.is_valid():
          return render(request, "login.html", {"form": form})
      
      # 手动读取字典,跟新数据至数据库
models.UserInfo.objects.filter(id=1).update(name=form.cleaned_data['name'], pwd=form.cleaned_data['pwd'])
      return HttpResponse("成功")
  • ModelForm组件
  def login(request):
      if request.method == "GET":
      	form = LoginModelForm()
      	return render(request, "login.html", {"form": form})
      
      user_object = model.UserInfo.object.filter(id=1).first()
      form = LoginModelForm(data=request.POST, instance=user_object)
      if not form.is_valid():
          return render(request, "login.html", {"form": form})
      
      form.save() # 更新id=1
      return HttpResponse("成功")

总结

  • 后续进行增删改查是基于数据库Models中的某个表,推荐使用:ModelForm;

  • 如果要进行表单校验是与数据库的表无关直接使用Form。

;