如何使用Django Form组件进行表单处理?

2026-05-22 23:182阅读0评论SEO问题
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计4024个文字,预计阅读时间需要17分钟。

Django Form组件介绍,包括form组件与传统form表单对比,验证字段实操,使用全局和局部钩子精确校验,全解析如下:

Django Form组件----------------

Django Form组件是Django框架中用于处理表单数据的核心工具。它可以帮助我们轻松地创建、验证和渲染HTML表单。

form组件与传统form表单对比

| 特性 | form组件 | 传统form表单 || ---------- | ---------------------------------- | ------------------------------------- || 易用性 | 高,提供多种内置字段和验证功能 | 低,需要手动编写HTML和JavaScript代码 || 验证 | 内置字段验证,易于扩展 | 需要手动编写验证逻辑 || 国际化 | 支持多语言,方便国际化 | 需要手动处理多语言问题 || 安全性 | 内置安全性检查,防止跨站请求伪造等 | 需要手动添加安全性检查 |

验证字段实操

要验证字段,可以在form类中定义相应的字段,并设置验证规则。以下是一个简单的示例:

pythonfrom django import forms

class MyForm(forms.Form): name=forms.CharField(max_length=100) email=forms.EmailField()

def clean_name(self): name=self.cleaned_data['name'] if len(name) <3: raise forms.ValidationError(Name must be at least 3 characters long.) return name

def clean_email(self): email=self.cleaned_data['email'] if '@' not in email: raise forms.ValidationError(Invalid email address.) return email

渲染标签样式

要自定义标签样式,可以使用`widget`属性或直接在HTML模板中修改。

pythonclass MyForm(forms.Form): name=forms.CharField(label=Your Name, widget=forms.TextInput(attrs={'class': 'form-control'}))

使用全局和局部钩子精确校验

全局钩子:在form验证开始前执行,适用于所有字段。

局部钩子:在特定字段验证时执行,适用于单个字段。

pythonclass MyForm(forms.Form): name=forms.CharField()

def clean(self): cleaned_data=super().clean() name=cleaned_data.get('name') if len(name) <3: raise forms.ValidationError(Name must be at least 3 characters long.) return cleaned_data

以上就是Django Form组件的介绍,希望对您有所帮助。

Django Form组件 如何校验字段,如何渲染标签样式,如何使用全局钩子和局部钩子来精准校验,全在这里!

目录
  • Django Form组件
    • 简介
    • form组件和传统form表单对比
    • 校验字段
      • 校验字段实操
    • forms渲染标签
      • 自己手动写HTML页面
      • forms渲染标签(一)
      • forms渲染标签(二)
      • forms渲染标签(三)
    • 渲染错误信息
        • 示例
    • form渲染样式之参数配置
    • forms组件全局钩子和局部勾子
      • 局部钩子
      • 全局钩子
    • 错误信息显示

Django Form组件

简介

Django Form 组件有两大功能,用于对页面进行初始化,生成 HTML 标签,此外还可以对用户提交对数据进行校验(显示错误信息)

  • 数据重置
  • 校验规则
form组件和传统form表单对比
  • 当我们用传统的form表单提交时会刷新页面,如果这个我们表单中的某项填错了,刷新后我们正确的选项也没有了
  • 传统的form表单需要我们自己亲自校验每一项,其工作量太大
  • form组件前端自动生成表单元素
  • form组件可自动验证表单内容信息
  • form组件可保留用户上次输入的信息

导入form django import froms

校验字段

ps:这里数据量较小使用sqlite3

# settings.py需要修改的配置 # LANGUAGE_CODE = 'en-us' LANGUAGE_CODE = 'zh-Hans' # 修改成中文 # TIME_ZONE = 'UTC' TIME_ZONE = 'Asia/Shanghai' # 时间使用上海的 USE_I18N = True USE_L10N = True USE_TZ = False # 改为当前时区,默认为True 校验字段实操

我们在不使用forms的情况下也可以校验用户注册的字段长度是否符合标准,比如通过len()等方法,但是过于麻烦,下面通过forms来校验用户字段长度;(注册举例)

''' 1.注册页面,forms校验,需要定义一个类,来继承forms.Form 2.自定义类内规定的字段就是校验规则 3.实例化类,得到form对象,使用is_valid校验,校验成功可以通过对象.cleanded.data获取到干净的数据,校验失败通过对象.erros返回错误信息 ''' 需要注意的是,实例化对象要传入校验数据! eg:reg_obj = Reg(data=request.POST)

'''Myforms.py''' from django import forms class Register(forms.Form): username = forms.CharField(max_length=8, min_length=3, label='用户名',error_messages={'min_length':'太短了',"required": "该字段不能为空!"}) password = forms.CharField(max_length=11, min_length=3, label='密码') re_password = forms.CharField(max_length=11, min_length=3, label='确认密码') email = forms.EmailField(label='邮箱')

  • label:输入框前面的文本信息。
  • error_message:自定义显示的错误信息,属性值是字典, 其中 required 为设置不能为空时显示的错误信息的 key

'''views.py''' from django.shortcuts import render,HttpResponse,redirect from app01.My_forms import Register def register(request): if request.method == 'GET': return render(request,'register.html') else: # 实例化,传入校验数据 reg_form_obj = Register(data=request.POST) # 判断校验是否可以通过 if reg_form_obj.is_valid(): # 校验通过存入数据库 print('校验通过') print(reg_form_obj.cleaned_data) reg_form_obj.cleaned_data.pop('re_password') data = reg_form_obj.cleaned_data models.Register.objects.create(**data) # 将校验通过的数据打散传入 else: # 校验不通过,返回错误信息 print('校验不通过') print(reg_form_obj.errors) return HttpResponse('ok') '''不理解打散可以看下面这几个示例''' # 字符串打散 s = 'Hammer' print(s) # Hammer print(*s) # H a m m e r # 元组打散 tup = (1,2,3) print(tup) # (1, 2, 3) print(*tup) # 1 2 3 # 列表打散 lst = [1,2,3] print(lst) # [1, 2, 3] print(*lst) # 1 2 3 # 字典打散 def func(name,age): print(name,age) dic = {'name':'Hammer','age':18} func(**dic) # Hammer 18

'''urls.py''' path('register/', views.register)

'''models.py''' from django.db import models class Register(models.Model): username = models.CharField(max_length=32) password = models.CharField(max_length=32) email = models.EmailField

<!--register.html--> <form action="" method="post"> <div class="container"> <h1 class="active" style="text-align: center">注册页面</h1> <div class="row"> <div class="col-md-8 col-md-offset-2"> <p>用户名: <input type="text" name="username" class="form-control"></p> <p>密码: <input type="password" name="password" class="form-control"></p> <p>确认密码: <input type="password" name="re_password" class="form-control"></p> <p>邮箱: <input type="email" name="email" class="form-control"></p> <input type="submit" value="提交" class="btn btn-block btn-info"> </div> </div> </div> </form>

# 校验不通过 校验不通过 <ul class="errorlist"><li>username<ul class="errorlist"><li>该字段不能为空!</li></ul></li></ul> # 校验通过 校验通过 {'username': 'HammerZe', 'password': '123', 're_password': '123', 'email': '456@qq.com'} forms渲染标签 自己手动写HTML页面

<form action="" method="post"> <div class="container"> <h1 class="active" style="text-align: center">注册页面</h1> <div class="row"> <div class="col-md-8 col-md-offset-2"> <p>用户名: <input type="text" name="username" class="form-control"></p> <p>密码: <input type="password" name="password" class="form-control"></p> <p>确认密码: <input type="password" name="re_password" class="form-control"></p> <p>邮箱: <input type="email" name="email" class="form-control"></p> <input type="submit" value="提交" class="btn btn-block btn-info"> </div> </div> </div> </form> forms渲染标签(一)

通过在视图函数中生成一个空form对象,html页面可以直接使用该对象进行渲染

def register(request): if request.method == 'GET': empty_form = Register() return render(request,'register.html',{'form':empty_form}) else: # 实例化,传入校验数据 reg_form_obj = Register(data=request.POST) # 判断校验是否可以通过 if reg_form_obj.is_valid(): # 校验通过存入数据库 print('校验通过') print(reg_form_obj.cleaned_data) else: # 校验不通过,返回错误信息 print('校验不通过') print(reg_form_obj.errors) return HttpResponse('ok')

{#forms渲染标签1#} <form action="" method="post"> <div class="container"> <h1 class="active" style="text-align: center">注册页面2</h1> <div class="row"> <div class="col-md-8 col-md-offset-2"> <p>用户名: {{ form.username }}</p> <p>密码: {{ form.password }}</p> <p>确认密码: {{ form.re_password }}</p> <p>邮箱: {{ form.email }}</p> <input type="submit" value="提交" class="btn btn-block btn-info"> </div> </div> </div> </form>

总结

如果使用forms渲染,前端会优化处理,如果长度超出会自动截取等优点

forms渲染标签(二)

标签页可以通过for循环form对象来渲染,标签前面的字段可以通过label属性来拿到,每循环一次foo就可以得到一个字段

{#forms渲染标签2#} <form action="" method="post"> <div class="container"> <h1 class="active" style="text-align: center">注册页面3</h1> <div class="row"> <div class="col-md-8 col-md-offset-2"> {% for foo in form %} <p>{{ foo.label }}:{{ foo }}</p> {% endfor %} <input type="submit" value="提交" class="btn btn-block btn-info"> </div> </div> </div> </form> forms渲染标签(三)

渲染标签也可以通过一句话来渲染,form.as_p,as_后面可以跟不同标签的名字,比如as_table,as_ul····,但是这样渲染标签直接写死,扩展性极低!

{#forms渲染标签3#} <form action="" method="post"> <div class="container"> <h1 class="active" style="text-align: center">注册页面4</h1> <div class="row"> <div class="col-md-8 col-md-offset-2"> {{ form.as_p }} {#{{ form.as_table }}#} <input type="submit" value="提交" class="btn btn-block btn-info"> </div> </div> </div> </form> 渲染错误信息

  • novalidate参数,form标签中使用,如果添加该参数,不需要校验或者使用自己的校验规则
  • 渲染错误信息需要传入error_messages参数在类中

error_messages参数中指定的参数类型

error_messages参数指定错误信息类型,以字典的形式指定

  • min_length:不满足最小长度渲染的信息
  • max_length:超过最大长度渲染的信息
  • required:非空,必填,如果没填渲染的信息
  • invalid:指定邮箱格式
示例

'''views.py''' def register(request): if request.method == 'GET': empty_form = Register() return render(request,'register.html',{'form':empty_form}) else: # 实例化,传入校验数据 reg_form_obj = Register(data=request.POST) # 判断校验是否可以通过 if reg_form_obj.is_valid(): # 校验通过存入数据库 print('校验通过') print(reg_form_obj.cleaned_data) reg_form_obj.cleaned_data.pop('re_password') data = reg_form_obj.cleaned_data models.Register.objects.create(**data) return HttpResponse('成功') # 校验通过返回一个成功 else: # 校验不通过,返回错误信息 print('校验不通过') print(reg_form_obj.errors) return render(request,'register.html',{'form':reg_form_obj})

校验通过和不通过分别返回不同的数据

<!--前端页面--> <form action="" method="post" novalidate> <h1 class="active" style="text-align: center">注册页面 {% for foo in form %} <p>{{ foo.label }}:{{ foo }}<span style="color: tomato">{{ foo.errors.0 }}</span></p> {% endfor %} <input type="submit" value="提交"> </form>

需要注意的是,foo.errors返回的是li标签,是多个,想看单个字段的错误信息要指定

form渲染样式之参数配置

上面这样直接使用渲染的标签是没有boostrap组件样式的,可以通过在类添加参数来定制样式

导入from django.forms import widgets

  • widget参数指定input框内的文本格式
  • attrs参数指定标签的样式

'''Myforms.py''' class Register(forms.Form): username = forms.CharField(max_length=8, min_length=3, label='用户名', error_messages={'min_length': '太短了吧,敢不敢大于3cm', "required": "该字段不能为空!"} ,widget=widgets.TextInput(attrs={'class':'form-control'})) password = forms.CharField(max_length=11, min_length=3, label='密码',widget=widgets.PasswordInput(attrs={'class':'form-control'})) re_password = forms.CharField(max_length=11, min_length=3, label='确认密码',widget=widgets.PasswordInput(attrs={'class':'form-control'})) email = forms.EmailField(label='邮箱', error_messages={'invalid': '格式不正确'},widget=widgets.EmailInput(attrs={'class':'form-control'}))

<form action="" method="post" novalidate> <div class="container"> <h1 class="active" style="text-align: center">注册页面3</h1> <div class="row"> <div class="col-md-8 col-md-offset-2"> {% for foo in form %} <p>{{ foo.label }}:{{ foo }}<span style="color: tomato">{{ foo.errors.0 }}</span></p> {% endfor %} <input type="submit" value="提交" class="btn btn-block btn-info"> </div> </div> </div> </form>

forms组件全局钩子和局部勾子

局部钩子使forms校验更加精准,比如限制字段长度,是否为数字等···

全局钩子可以拿到部分字段进行比较,比如确认两次输入的密码是否一致,或者两次的内容是否一致等···

局部钩子

from django import forms from django.core.exceptions import ValidationError from django.forms import widgets class Register(forms.Form): username = forms.CharField(max_length=8, min_length=3, label='用户名', error_messages={'min_length': '太短了吧,敢不敢大于3cm', "required": "该字段不能为空!"} , widget=widgets.TextInput(attrs={'class': 'form-control'})) password = forms.CharField(max_length=11, min_length=3, label='密码', widget=widgets.PasswordInput(attrs={'class': 'form-control'})) re_password = forms.CharField(max_length=11, min_length=3, label='确认密码', widget=widgets.PasswordInput(attrs={'class': 'form-control'})) email = forms.EmailField(label='邮箱', error_messages={'invalid': '格式不正确'}, widget=widgets.EmailInput(attrs={'class': 'form-control'})) def clean_username(self): # 局部钩子 # 校验名字不能以sb开头 username = self.cleaned_data.get('username') if username.startswith('sb'): # 校验不通过,抛出异常 raise ValidationError('不能以sb开头') else: return username # 校验通过,返回username对应的值,这里不返回username值,后面视图函数取不到

总结

  • 抛出异常模块:from django.core.exceptions import ValidationError
  • 局部钩子需要注意的是,自定义函数后面需要加对应字段的名字,比如clean_username,以及校验通过后面要返回校验的字段,不然后面拿不到值
全局钩子

from django import forms from django.core.exceptions import ValidationError from django.forms import widgets class Register(forms.Form): username = forms.CharField(max_length=8, min_length=3, label='用户名', error_messages={'min_length': '太短了吧,敢不敢大于3cm', "required": "该字段不能为空!"} , widget=widgets.TextInput(attrs={'class': 'form-control'})) password = forms.CharField(max_length=11, min_length=3, label='密码', widget=widgets.PasswordInput(attrs={'class': 'form-control'})) re_password = forms.CharField(max_length=11, min_length=3, label='确认密码', widget=widgets.PasswordInput(attrs={'class': 'form-control'})) email = forms.EmailField(label='邮箱', error_messages={'invalid': '格式不正确'}, widget=widgets.EmailInput(attrs={'class': 'form-control'})) def clean_username(self): # 局部钩子 # 校验名字不能以sb开头 username = self.cleaned_data.get('username') if username.startswith('sb'): # 校验不通过,抛出异常 raise ValidationError('不能以sb开头') else: return username # 校验通过,返回username对应的值,这里不返回username值,后面视图函数取不到 def clean(self): # 全局钩子 password = self.cleaned_data.get('password') re_password = self.cleaned_data.get('re_password') if password == re_password: return self.cleaned_data # 返回所有校验通过的数据 else: raise ValidationError('两次密码不一致')

from django.shortcuts import render,HttpResponse,redirect from app01.My_forms import Register from app01 import models def register(request): if request.method == 'GET': empty_form = Register() return render(request,'register.html',{'form':empty_form}) else: # 实例化,传入校验数据 reg_form_obj = Register(data=request.POST) # 判断校验是否可以通过 if reg_form_obj.is_valid(): # 校验通过存入数据库 print('校验通过') print(reg_form_obj.cleaned_data) reg_form_obj.cleaned_data.pop('re_password') data = reg_form_obj.cleaned_data models.Register.objects.create(**data) return HttpResponse('成功') # 校验通过返回一个成功 else: # 校验不通过,返回错误信息 print('校验不通过') print(reg_form_obj.errors) global_error = reg_form_obj.errors.get('__all__')[0] # 全局钩子错误 # local_error = reg_form_obj.errors.get('username')[0] # 局部钩子错误 return render(request,'register.html',{'form':reg_form_obj,'global_error':global_error})

<form action="" method="post" novalidate> <div class="container"> <h1 class="active" style="text-align: center">注册页面3</h1> <div class="row"> <div class="col-md-8 col-md-offset-2"> {% for foo in form %} <p>{{ foo.label }}:{{ foo }}<span style="color: tomato">{{ foo.errors.0 }}</span></p> {% endfor %} <input type="submit" value="提交" class="btn btn-block btn-info"> <span style="color: #aa100e">{{ global_error }}</span> </div> </div> </div> </form>

总结

  • 全局钩子获取错误可以通过__all__获取
  • 渲染标签或者页面要实例化form空对象
错误信息显示

报错信息显示顺序:

  • 先显示字段属性中的错误信息,然后再显示局部钩子的错误信息。
  • 若显示了字段属性的错误信息,就不会显示局部钩子的错误信息。
  • 若有全局钩子,则全局钩子是等所有的数据都校验完,才开始进行校验,并且全局钩子的错误信息一定会显示

本文共计4024个文字,预计阅读时间需要17分钟。

Django Form组件介绍,包括form组件与传统form表单对比,验证字段实操,使用全局和局部钩子精确校验,全解析如下:

Django Form组件----------------

Django Form组件是Django框架中用于处理表单数据的核心工具。它可以帮助我们轻松地创建、验证和渲染HTML表单。

form组件与传统form表单对比

| 特性 | form组件 | 传统form表单 || ---------- | ---------------------------------- | ------------------------------------- || 易用性 | 高,提供多种内置字段和验证功能 | 低,需要手动编写HTML和JavaScript代码 || 验证 | 内置字段验证,易于扩展 | 需要手动编写验证逻辑 || 国际化 | 支持多语言,方便国际化 | 需要手动处理多语言问题 || 安全性 | 内置安全性检查,防止跨站请求伪造等 | 需要手动添加安全性检查 |

验证字段实操

要验证字段,可以在form类中定义相应的字段,并设置验证规则。以下是一个简单的示例:

pythonfrom django import forms

class MyForm(forms.Form): name=forms.CharField(max_length=100) email=forms.EmailField()

def clean_name(self): name=self.cleaned_data['name'] if len(name) <3: raise forms.ValidationError(Name must be at least 3 characters long.) return name

def clean_email(self): email=self.cleaned_data['email'] if '@' not in email: raise forms.ValidationError(Invalid email address.) return email

渲染标签样式

要自定义标签样式,可以使用`widget`属性或直接在HTML模板中修改。

pythonclass MyForm(forms.Form): name=forms.CharField(label=Your Name, widget=forms.TextInput(attrs={'class': 'form-control'}))

使用全局和局部钩子精确校验

全局钩子:在form验证开始前执行,适用于所有字段。

局部钩子:在特定字段验证时执行,适用于单个字段。

pythonclass MyForm(forms.Form): name=forms.CharField()

def clean(self): cleaned_data=super().clean() name=cleaned_data.get('name') if len(name) <3: raise forms.ValidationError(Name must be at least 3 characters long.) return cleaned_data

以上就是Django Form组件的介绍,希望对您有所帮助。

Django Form组件 如何校验字段,如何渲染标签样式,如何使用全局钩子和局部钩子来精准校验,全在这里!

目录
  • Django Form组件
    • 简介
    • form组件和传统form表单对比
    • 校验字段
      • 校验字段实操
    • forms渲染标签
      • 自己手动写HTML页面
      • forms渲染标签(一)
      • forms渲染标签(二)
      • forms渲染标签(三)
    • 渲染错误信息
        • 示例
    • form渲染样式之参数配置
    • forms组件全局钩子和局部勾子
      • 局部钩子
      • 全局钩子
    • 错误信息显示

Django Form组件

简介

Django Form 组件有两大功能,用于对页面进行初始化,生成 HTML 标签,此外还可以对用户提交对数据进行校验(显示错误信息)

  • 数据重置
  • 校验规则
form组件和传统form表单对比
  • 当我们用传统的form表单提交时会刷新页面,如果这个我们表单中的某项填错了,刷新后我们正确的选项也没有了
  • 传统的form表单需要我们自己亲自校验每一项,其工作量太大
  • form组件前端自动生成表单元素
  • form组件可自动验证表单内容信息
  • form组件可保留用户上次输入的信息

导入form django import froms

校验字段

ps:这里数据量较小使用sqlite3

# settings.py需要修改的配置 # LANGUAGE_CODE = 'en-us' LANGUAGE_CODE = 'zh-Hans' # 修改成中文 # TIME_ZONE = 'UTC' TIME_ZONE = 'Asia/Shanghai' # 时间使用上海的 USE_I18N = True USE_L10N = True USE_TZ = False # 改为当前时区,默认为True 校验字段实操

我们在不使用forms的情况下也可以校验用户注册的字段长度是否符合标准,比如通过len()等方法,但是过于麻烦,下面通过forms来校验用户字段长度;(注册举例)

''' 1.注册页面,forms校验,需要定义一个类,来继承forms.Form 2.自定义类内规定的字段就是校验规则 3.实例化类,得到form对象,使用is_valid校验,校验成功可以通过对象.cleanded.data获取到干净的数据,校验失败通过对象.erros返回错误信息 ''' 需要注意的是,实例化对象要传入校验数据! eg:reg_obj = Reg(data=request.POST)

'''Myforms.py''' from django import forms class Register(forms.Form): username = forms.CharField(max_length=8, min_length=3, label='用户名',error_messages={'min_length':'太短了',"required": "该字段不能为空!"}) password = forms.CharField(max_length=11, min_length=3, label='密码') re_password = forms.CharField(max_length=11, min_length=3, label='确认密码') email = forms.EmailField(label='邮箱')

  • label:输入框前面的文本信息。
  • error_message:自定义显示的错误信息,属性值是字典, 其中 required 为设置不能为空时显示的错误信息的 key

'''views.py''' from django.shortcuts import render,HttpResponse,redirect from app01.My_forms import Register def register(request): if request.method == 'GET': return render(request,'register.html') else: # 实例化,传入校验数据 reg_form_obj = Register(data=request.POST) # 判断校验是否可以通过 if reg_form_obj.is_valid(): # 校验通过存入数据库 print('校验通过') print(reg_form_obj.cleaned_data) reg_form_obj.cleaned_data.pop('re_password') data = reg_form_obj.cleaned_data models.Register.objects.create(**data) # 将校验通过的数据打散传入 else: # 校验不通过,返回错误信息 print('校验不通过') print(reg_form_obj.errors) return HttpResponse('ok') '''不理解打散可以看下面这几个示例''' # 字符串打散 s = 'Hammer' print(s) # Hammer print(*s) # H a m m e r # 元组打散 tup = (1,2,3) print(tup) # (1, 2, 3) print(*tup) # 1 2 3 # 列表打散 lst = [1,2,3] print(lst) # [1, 2, 3] print(*lst) # 1 2 3 # 字典打散 def func(name,age): print(name,age) dic = {'name':'Hammer','age':18} func(**dic) # Hammer 18

'''urls.py''' path('register/', views.register)

'''models.py''' from django.db import models class Register(models.Model): username = models.CharField(max_length=32) password = models.CharField(max_length=32) email = models.EmailField

<!--register.html--> <form action="" method="post"> <div class="container"> <h1 class="active" style="text-align: center">注册页面</h1> <div class="row"> <div class="col-md-8 col-md-offset-2"> <p>用户名: <input type="text" name="username" class="form-control"></p> <p>密码: <input type="password" name="password" class="form-control"></p> <p>确认密码: <input type="password" name="re_password" class="form-control"></p> <p>邮箱: <input type="email" name="email" class="form-control"></p> <input type="submit" value="提交" class="btn btn-block btn-info"> </div> </div> </div> </form>

# 校验不通过 校验不通过 <ul class="errorlist"><li>username<ul class="errorlist"><li>该字段不能为空!</li></ul></li></ul> # 校验通过 校验通过 {'username': 'HammerZe', 'password': '123', 're_password': '123', 'email': '456@qq.com'} forms渲染标签 自己手动写HTML页面

<form action="" method="post"> <div class="container"> <h1 class="active" style="text-align: center">注册页面</h1> <div class="row"> <div class="col-md-8 col-md-offset-2"> <p>用户名: <input type="text" name="username" class="form-control"></p> <p>密码: <input type="password" name="password" class="form-control"></p> <p>确认密码: <input type="password" name="re_password" class="form-control"></p> <p>邮箱: <input type="email" name="email" class="form-control"></p> <input type="submit" value="提交" class="btn btn-block btn-info"> </div> </div> </div> </form> forms渲染标签(一)

通过在视图函数中生成一个空form对象,html页面可以直接使用该对象进行渲染

def register(request): if request.method == 'GET': empty_form = Register() return render(request,'register.html',{'form':empty_form}) else: # 实例化,传入校验数据 reg_form_obj = Register(data=request.POST) # 判断校验是否可以通过 if reg_form_obj.is_valid(): # 校验通过存入数据库 print('校验通过') print(reg_form_obj.cleaned_data) else: # 校验不通过,返回错误信息 print('校验不通过') print(reg_form_obj.errors) return HttpResponse('ok')

{#forms渲染标签1#} <form action="" method="post"> <div class="container"> <h1 class="active" style="text-align: center">注册页面2</h1> <div class="row"> <div class="col-md-8 col-md-offset-2"> <p>用户名: {{ form.username }}</p> <p>密码: {{ form.password }}</p> <p>确认密码: {{ form.re_password }}</p> <p>邮箱: {{ form.email }}</p> <input type="submit" value="提交" class="btn btn-block btn-info"> </div> </div> </div> </form>

总结

如果使用forms渲染,前端会优化处理,如果长度超出会自动截取等优点

forms渲染标签(二)

标签页可以通过for循环form对象来渲染,标签前面的字段可以通过label属性来拿到,每循环一次foo就可以得到一个字段

{#forms渲染标签2#} <form action="" method="post"> <div class="container"> <h1 class="active" style="text-align: center">注册页面3</h1> <div class="row"> <div class="col-md-8 col-md-offset-2"> {% for foo in form %} <p>{{ foo.label }}:{{ foo }}</p> {% endfor %} <input type="submit" value="提交" class="btn btn-block btn-info"> </div> </div> </div> </form> forms渲染标签(三)

渲染标签也可以通过一句话来渲染,form.as_p,as_后面可以跟不同标签的名字,比如as_table,as_ul····,但是这样渲染标签直接写死,扩展性极低!

{#forms渲染标签3#} <form action="" method="post"> <div class="container"> <h1 class="active" style="text-align: center">注册页面4</h1> <div class="row"> <div class="col-md-8 col-md-offset-2"> {{ form.as_p }} {#{{ form.as_table }}#} <input type="submit" value="提交" class="btn btn-block btn-info"> </div> </div> </div> </form> 渲染错误信息

  • novalidate参数,form标签中使用,如果添加该参数,不需要校验或者使用自己的校验规则
  • 渲染错误信息需要传入error_messages参数在类中

error_messages参数中指定的参数类型

error_messages参数指定错误信息类型,以字典的形式指定

  • min_length:不满足最小长度渲染的信息
  • max_length:超过最大长度渲染的信息
  • required:非空,必填,如果没填渲染的信息
  • invalid:指定邮箱格式
示例

'''views.py''' def register(request): if request.method == 'GET': empty_form = Register() return render(request,'register.html',{'form':empty_form}) else: # 实例化,传入校验数据 reg_form_obj = Register(data=request.POST) # 判断校验是否可以通过 if reg_form_obj.is_valid(): # 校验通过存入数据库 print('校验通过') print(reg_form_obj.cleaned_data) reg_form_obj.cleaned_data.pop('re_password') data = reg_form_obj.cleaned_data models.Register.objects.create(**data) return HttpResponse('成功') # 校验通过返回一个成功 else: # 校验不通过,返回错误信息 print('校验不通过') print(reg_form_obj.errors) return render(request,'register.html',{'form':reg_form_obj})

校验通过和不通过分别返回不同的数据

<!--前端页面--> <form action="" method="post" novalidate> <h1 class="active" style="text-align: center">注册页面 {% for foo in form %} <p>{{ foo.label }}:{{ foo }}<span style="color: tomato">{{ foo.errors.0 }}</span></p> {% endfor %} <input type="submit" value="提交"> </form>

需要注意的是,foo.errors返回的是li标签,是多个,想看单个字段的错误信息要指定

form渲染样式之参数配置

上面这样直接使用渲染的标签是没有boostrap组件样式的,可以通过在类添加参数来定制样式

导入from django.forms import widgets

  • widget参数指定input框内的文本格式
  • attrs参数指定标签的样式

'''Myforms.py''' class Register(forms.Form): username = forms.CharField(max_length=8, min_length=3, label='用户名', error_messages={'min_length': '太短了吧,敢不敢大于3cm', "required": "该字段不能为空!"} ,widget=widgets.TextInput(attrs={'class':'form-control'})) password = forms.CharField(max_length=11, min_length=3, label='密码',widget=widgets.PasswordInput(attrs={'class':'form-control'})) re_password = forms.CharField(max_length=11, min_length=3, label='确认密码',widget=widgets.PasswordInput(attrs={'class':'form-control'})) email = forms.EmailField(label='邮箱', error_messages={'invalid': '格式不正确'},widget=widgets.EmailInput(attrs={'class':'form-control'}))

<form action="" method="post" novalidate> <div class="container"> <h1 class="active" style="text-align: center">注册页面3</h1> <div class="row"> <div class="col-md-8 col-md-offset-2"> {% for foo in form %} <p>{{ foo.label }}:{{ foo }}<span style="color: tomato">{{ foo.errors.0 }}</span></p> {% endfor %} <input type="submit" value="提交" class="btn btn-block btn-info"> </div> </div> </div> </form>

forms组件全局钩子和局部勾子

局部钩子使forms校验更加精准,比如限制字段长度,是否为数字等···

全局钩子可以拿到部分字段进行比较,比如确认两次输入的密码是否一致,或者两次的内容是否一致等···

局部钩子

from django import forms from django.core.exceptions import ValidationError from django.forms import widgets class Register(forms.Form): username = forms.CharField(max_length=8, min_length=3, label='用户名', error_messages={'min_length': '太短了吧,敢不敢大于3cm', "required": "该字段不能为空!"} , widget=widgets.TextInput(attrs={'class': 'form-control'})) password = forms.CharField(max_length=11, min_length=3, label='密码', widget=widgets.PasswordInput(attrs={'class': 'form-control'})) re_password = forms.CharField(max_length=11, min_length=3, label='确认密码', widget=widgets.PasswordInput(attrs={'class': 'form-control'})) email = forms.EmailField(label='邮箱', error_messages={'invalid': '格式不正确'}, widget=widgets.EmailInput(attrs={'class': 'form-control'})) def clean_username(self): # 局部钩子 # 校验名字不能以sb开头 username = self.cleaned_data.get('username') if username.startswith('sb'): # 校验不通过,抛出异常 raise ValidationError('不能以sb开头') else: return username # 校验通过,返回username对应的值,这里不返回username值,后面视图函数取不到

总结

  • 抛出异常模块:from django.core.exceptions import ValidationError
  • 局部钩子需要注意的是,自定义函数后面需要加对应字段的名字,比如clean_username,以及校验通过后面要返回校验的字段,不然后面拿不到值
全局钩子

from django import forms from django.core.exceptions import ValidationError from django.forms import widgets class Register(forms.Form): username = forms.CharField(max_length=8, min_length=3, label='用户名', error_messages={'min_length': '太短了吧,敢不敢大于3cm', "required": "该字段不能为空!"} , widget=widgets.TextInput(attrs={'class': 'form-control'})) password = forms.CharField(max_length=11, min_length=3, label='密码', widget=widgets.PasswordInput(attrs={'class': 'form-control'})) re_password = forms.CharField(max_length=11, min_length=3, label='确认密码', widget=widgets.PasswordInput(attrs={'class': 'form-control'})) email = forms.EmailField(label='邮箱', error_messages={'invalid': '格式不正确'}, widget=widgets.EmailInput(attrs={'class': 'form-control'})) def clean_username(self): # 局部钩子 # 校验名字不能以sb开头 username = self.cleaned_data.get('username') if username.startswith('sb'): # 校验不通过,抛出异常 raise ValidationError('不能以sb开头') else: return username # 校验通过,返回username对应的值,这里不返回username值,后面视图函数取不到 def clean(self): # 全局钩子 password = self.cleaned_data.get('password') re_password = self.cleaned_data.get('re_password') if password == re_password: return self.cleaned_data # 返回所有校验通过的数据 else: raise ValidationError('两次密码不一致')

from django.shortcuts import render,HttpResponse,redirect from app01.My_forms import Register from app01 import models def register(request): if request.method == 'GET': empty_form = Register() return render(request,'register.html',{'form':empty_form}) else: # 实例化,传入校验数据 reg_form_obj = Register(data=request.POST) # 判断校验是否可以通过 if reg_form_obj.is_valid(): # 校验通过存入数据库 print('校验通过') print(reg_form_obj.cleaned_data) reg_form_obj.cleaned_data.pop('re_password') data = reg_form_obj.cleaned_data models.Register.objects.create(**data) return HttpResponse('成功') # 校验通过返回一个成功 else: # 校验不通过,返回错误信息 print('校验不通过') print(reg_form_obj.errors) global_error = reg_form_obj.errors.get('__all__')[0] # 全局钩子错误 # local_error = reg_form_obj.errors.get('username')[0] # 局部钩子错误 return render(request,'register.html',{'form':reg_form_obj,'global_error':global_error})

<form action="" method="post" novalidate> <div class="container"> <h1 class="active" style="text-align: center">注册页面3</h1> <div class="row"> <div class="col-md-8 col-md-offset-2"> {% for foo in form %} <p>{{ foo.label }}:{{ foo }}<span style="color: tomato">{{ foo.errors.0 }}</span></p> {% endfor %} <input type="submit" value="提交" class="btn btn-block btn-info"> <span style="color: #aa100e">{{ global_error }}</span> </div> </div> </div> </form>

总结

  • 全局钩子获取错误可以通过__all__获取
  • 渲染标签或者页面要实例化form空对象
错误信息显示

报错信息显示顺序:

  • 先显示字段属性中的错误信息,然后再显示局部钩子的错误信息。
  • 若显示了字段属性的错误信息,就不会显示局部钩子的错误信息。
  • 若有全局钩子,则全局钩子是等所有的数据都校验完,才开始进行校验,并且全局钩子的错误信息一定会显示