froms组件前戏

需求:

  1. """
  2. 写一个注册功能
  3. 获取用户名和密码 利用form表单提交数据
  4. 在后端判断用户名和密码是否符合一定的条件
  5. 用户名中不能含有666
  6. 密码不能少于三位
  7. 如何符合条件需要你将提示信息展示到前端页面
  8. """

普通方式实现(不结合ajax)

views.py

  1. from django.shortcuts import render
  2. # Create your views here.
  3. def ab_form(request):
  4. back_dic = {"username":"","password":""}
  5. if request.method == "POST":
  6. username = request.POST.get("username")
  7. password = request.POST.get("password")
  8. if "666" in username:
  9. back_dic["username"] = "*用户名不合法"
  10. if len(password) < 3:
  11. back_dic["password"] = "*密码长度小于3"
  12. return render(request,"ab_form.html",locals())
  13. """
  14. 无论是post请求还是get请求
  15. 页面都能够获取到字典 只不过get请求来的时候 字典值都是空的
  16. 而post请求来之后 字典可能有值
  17. """

ab_form.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. <!-- Bootstrap3 核心 CSS 文件 -->
  7. <link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
  8. <!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
  9. <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
  10. <!-- Bootstrap3 核心 JavaScript 文件 -->
  11. <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
  12. <!-- font-awesome.min.css图标库4.7版本 -->
  13. <link href="https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
  14. </head>
  15. <body>
  16. <div class="container-fluid">
  17. <div class="row">
  18. <div class="col-md-8 col-md-offset-2">
  19. <form action="" method="post">
  20. <p>username:
  21. <input type="text" class="form-control" name="username">
  22. <span style="color: red">{{ back_dic.username }}</span>
  23. </p>
  24. <p>password:
  25. <input type="text" class="form-control" name="password">
  26. <span style="color: red">{{ back_dic.password }}</span>
  27. </p>
  28. <input type="submit" class="btn btn-info btn-block">
  29. </form>
  30. </div>
  31. </div>
  32. </div>
  33. </body>
  34. </html>

效果:

Django之forms组件 - 图1

使用到的技术点

  1. # 1.手动书写前端获取用户数据的html代码 渲染html代码
  2. # 2.后端对用户数据进行校验 校验数据
  3. # 3.对不符合要求的数据进行前端提示 展示提示信息

forms组件实现

forms组件能够完成的事情:

  1. # 1.渲染html代码
  2. # 2.校验数据
  3. # 3.展示提示信息

urls.py

  1. from django.conf.urls import url
  2. from django.contrib import admin
  3. from app01 import views
  4. urlpatterns = [
  5. url(r'^admin/', admin.site.urls),
  6. # forms组件
  7. url(r'^ab_form/', views.ab_form),
  8. ]
  9. urls.py

views.py,本文forms是直接写在views.py中的,也可以在app01应用中单独建一个文件夹或py文件解耦合,然后再views.py中导入

  1. from django.shortcuts import render,HttpResponse
  2. # 基本使用
  3. from django import forms # forms组件所需模块
  4. class MyForms(forms.Form):
  5. # username字符串类型最小3位最大8位
  6. username = forms.CharField(max_length=8,min_length=3,label="用户名",
  7. error_messages={
  8. 'min_length':'用户名最少3位',
  9. 'max_length':'用户名最大8位',
  10. 'required':"用户名不能为空"
  11. }
  12. )
  13. # password字符串类型最小3位最大8位
  14. password = forms.CharField(max_length=8,min_length=3,label="密码",
  15. error_messages = {
  16. 'min_length': '密码最少3位',
  17. 'max_length': '密码最大8位',
  18. 'required': "密码不能为空"
  19. }
  20. )
  21. # email字段必须符合邮箱格式 xxx@xx.com
  22. email = forms.EmailField(label="邮箱",
  23. error_messages={
  24. 'invalid': '邮箱格式不正确',
  25. 'required': "邮箱不能为空"
  26. }
  27. )
  28. # 钩子函数
  29. # 局部钩子
  30. def clean_username(self): # 用来校验username,走这一步前提是上面username字段条件满足了
  31. # 获取到用户名
  32. username = self.cleaned_data.get("username")
  33. if '666' in username:
  34. # 提示前端展示报错信息
  35. self.add_error("username","用户名不合法") # 添加一个错误信息,第一个参数是给哪个字段增加错误信息,第二个参数是错误信息内容
  36. # 将钩子函数钩取到的数据再放回去
  37. return username
  38. # 校验数据
  39. def ab_form(request):
  40. # 1 先产生一个空对象
  41. form_obj = MyForms()
  42. if request.method == "POST":
  43. # 获取用户数据
  44. """
  45. 1.数据获取繁琐
  46. 2.校验数据需要构造成字典的格式传入才行
  47. ps:但是request.POST可以看成就是一个字典
  48. """
  49. # 3.校验数据
  50. form_obj = MyForms(request.POST)
  51. # 4.判断数据是否合法
  52. if form_obj.is_valid():
  53. # 5.如果合法 操作数据库存储数据
  54. return HttpResponse('OK')
  55. # 5.不合法 有错误
  56. return render(request,"ab_form.html",locals())

ab_form.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. <!-- Bootstrap3 核心 CSS 文件 -->
  7. <link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
  8. <!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
  9. <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
  10. <!-- Bootstrap3 核心 JavaScript 文件 -->
  11. <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
  12. <!-- font-awesome.min.css图标库4.7版本 -->
  13. <link href="https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
  14. </head>
  15. <body>
  16. <div class="container-fluid">
  17. <div class="row">
  18. <div class="col-md-8 col-md-offset-2">
  19. <form action="" method="post" novalidate>
  20. {% for form in form_obj %}
  21. <p>
  22. {{ form.label }}:{{ form }}
  23. <span style="color: red">{{ form.errors.0 }}</span>
  24. </p>
  25. {% endfor %}
  26. <input type="submit" class="btn btn-info">
  27. </form>
  28. </div>
  29. </div>
  30. </div>
  31. </body>
  32. </html>

效果

Django之forms组件 - 图2

补充:

  1. 为什么数据校验非要去后端 不能在前端利用js直接完成呢?
  2. 数据校验前端可有可无
  3. 但是后端必须要有!!!
  4. 因为前端的校验是弱不禁风的 你可以直接修改
  5. 或者利用爬虫程序绕过前端页面直接朝后端提交数据
  6. 购物网站
  7. 选取了货物之后 会计算一个价格发送给后端 如果后端不做价格的校验
  8. 实际是获取到用户选择的所有商品的主键值
  9. 然后在后端查询出所有商品的价格 再次计算一遍
  10. 如果跟前端一致 那么完成支付如果不一致直接拒绝

forms组件基本使用

  1. from django.shortcuts import render
  2. # 基本使用
  3. from django import forms # forms组件所需模块
  4. class MyForms(forms.Form):
  5. # username字符串类型最小3位最大8位
  6. username = forms.CharField(max_length=8,min_length=3)
  7. # password字符串类型最小3位最大8位
  8. password = forms.CharField(max_length=8,min_length=3)
  9. # email字段必须符合邮箱格式 xxx@xx.com
  10. email = forms.EmailField()

froms组件校验数据

  1. """
  2. 1.测试环境的准备 可以自己拷贝代码准备
  3. 2.其实在pycharm里面已经帮你准备一个测试环境
  4. python console
  5. """

在python console操作示例:

  1. from app01 import views
  2. # 1 将带校验的数据组织成字典的形式传入即可
  3. form_obj = views.MyForm({'username':'jason','password':'123','email':'123'})
  4. # 2 判断数据是否合法 注意该方法只有在所有的数据全部合法的情况下才会返回True
  5. form_obj.is_valid()
  6. False
  7. # 3 查看所有校验通过的数据
  8. form_obj.cleaned_data
  9. {'username': 'jason', 'password': '123'}
  10. # 4 查看所有不符合校验规则以及不符合的原因
  11. form_obj.errors
  12. {
  13. 'email': ['Enter a valid email address.']
  14. }
  15. # 5 校验数据只校验类中出现的字段 多传不影响 多传的字段直接忽略
  16. form_obj = views.MyForm({'username':'jason','password':'123','email':'123@qq.com','hobby':'study'})
  17. form_obj.is_valid()
  18. True
  19. # 6 校验数据 默认情况下 类里面所有的字段都必须传值
  20. form_obj = views.MyForm({'username':'jason','password':'123'})
  21. form_obj.is_valid()
  22. False
  23. """
  24. 也就意味着校验数据的时候 默认情况下数据可以多传但是绝不可能少传
  25. """

forms渲染标签

  1. """
  2. forms组件只会自动帮你渲染获取用户输入的标签(input select radio checkbox)
  3. 不能帮你渲染提交按钮
  4. """

三种渲染方式:

views.py

  1. from django.shortcuts import render,HttpResponse
  2. # 基本使用
  3. from django import forms # forms组件所需模块
  4. class MyForms(forms.Form):
  5. # username字符串类型最小3位最大8位
  6. username = forms.CharField(max_length=8,min_length=3)
  7. # password字符串类型最小3位最大8位
  8. password = forms.CharField(max_length=8,min_length=3)
  9. # email字段必须符合邮箱格式 xxx@xx.com
  10. email = forms.EmailField()
  11. # 校验数据
  12. def ab_form(request):
  13. # 1 先产生一个空对象
  14. form_obj = MyForms()
  15. # 2 直接将该空对象传递给html页面
  16. return render(request,"ab_form.html",locals())

ab_form.html,前端利用空对象做操作

第一种渲染方式:

  1. <form action="" method="post">
  2. <p>第一种渲染方式:代码书写极少,封装程度太高 不便于后续的扩展 一般情况下只在本地测试使用</p>
  3. {{ form_obj.as_p }}
  4. {{ form_obj.as_ul }}
  5. {{ form_obj.as_table }}
  6. <input type="submit" class="btn btn-info btn-block">
  7. </form>

Django之forms组件 - 图3

第二种渲染方式:

  1. <form action="" method="post">
  2. <p>第二种渲染方式:可扩展性很强 但是需要书写的代码太多 一般情况下不用</p>
  3. <!--form_obj.username(forms类中的字段名):会帮你渲染一个name属性值为username(那个类中字段名)的input框-->
  4. <!--form_obj.username.label:拿到标签注释-->
  5. <p>{{ form_obj.username.label }}:{{ form_obj.username }}</p>
  6. <p>{{ form_obj.password.label }}:{{ form_obj.password }}</p>
  7. <p>{{ form_obj.email.label }}:{{ form_obj.email }}</p>
  8. <input type="submit" class="btn btn-info btn-block">
  9. </form>

补充:

  1. """
  2. label属性默认展示的是类中定义的字段首字母大写的形式
  3. 也可以自己修改 直接给forms类中字段对象加label属性即可
  4. username = forms.CharField(min_length=3,max_length=8,label='用户名')
  5. """

示例:

  1. from django.shortcuts import render,HttpResponse
  2. # 基本使用
  3. from django import forms # forms组件所需模块
  4. class MyForms(forms.Form):
  5. # username字符串类型最小3位最大8位
  6. username = forms.CharField(max_length=8,min_length=3,label="用户名")
  7. # password字符串类型最小3位最大8位
  8. password = forms.CharField(max_length=8,min_length=3,label="密码")
  9. # email字段必须符合邮箱格式 xxx@xx.com
  10. email = forms.EmailField(label="邮箱")
  11. # 校验数据
  12. def ab_form(request):
  13. # 1 先产生一个空对象
  14. form_obj = MyForms()
  15. # 2 直接将该空对象传递给html页面
  16. return render(request,"ab_form.html",locals())
  17. 字段添加label属性

效果:

Django之forms组件 - 图4

第三种渲染方式

  1. <form action="" method="post">
  2. <p>第三种渲染方式(推荐使用):代码书写简单 并且扩展性也高</p>
  3. {% for form in form_obj %} <!--此时的form等价于form_obj.username-->
  4. <p>{{ form.label }}:{{ form }}</p>
  5. {% endfor %}
  6. <input type="submit" class="btn btn-info btn-block">
  7. </form>

效果:

Django之forms组件 - 图5

渲染标签总结:

  1. """
  2. forms组件只会自动帮你渲染获取用户输入的标签(input select radio checkbox)
  3. 不能帮你渲染提交按钮
  4. """
  5. def index(request):
  6. # 1 先产生一个空对象
  7. form_obj = MyForm()
  8. # 2 直接将该空对象传递给html页面
  9. return render(request,'index.html',locals())
  10. # 前端利用空对象做操作
  11. <p>第一种渲染方式:代码书写极少,封装程度太高 不便于后续的扩展 一般情况下只在本地测试使用</p>
  12. {{ form_obj.as_p }}
  13. {{ form_obj.as_ul }}
  14. {{ form_obj.as_table }}
  15. <p>第二种渲染方式:可扩展性很强 但是需要书写的代码太多 一般情况下不用</p>
  16. <p>{{ form_obj.username.label }}:{{ form_obj.username }}</p>
  17. <p>{{ form_obj.password.label }}:{{ form_obj.password }}</p>
  18. <p>{{ form_obj.email.label }}:{{ form_obj.email }}</p>
  19. <p>第三种渲染方式(推荐使用):代码书写简单 并且扩展性也高</p>
  20. {% for form in form_obj %}
  21. <p>{{ form.label }}:{{ form }}</p>
  22. {% endfor %}
  23. """
  24. 字段的label属性默认展示的是类中定义的字段首字母大写的形式
  25. 也可以自己修改 直接给字段对象加label属性即可
  26. username = forms.CharField(min_length=3,max_length=8,label='用户名')
  27. """

补充:可以通过auto_id获取forms渲染的input框的id

  1. {% for form in form_obj %}
  2. <div class="from-group">
  3. <!--form.auto_id获取forms渲染的input框的id-->
  4. <label for="{{ form.auto_id }}">{{ form.label }}</label>
  5. {{ form }}
  6. <span style="color: red" class="pull-right"></span>
  7. </div>
  8. {% endfor %}

forms展示提示信息

示例:

urls.py

  1. from django.conf.urls import url
  2. from django.contrib import admin
  3. from app01 import views
  4. urlpatterns = [
  5. url(r'^admin/', admin.site.urls),
  6. # forms组件
  7. url(r'^ab_form/', views.ab_form),
  8. ]
  9. urls.py

views.py

  1. from django.shortcuts import render,HttpResponse
  2. # 基本使用
  3. from django import forms # forms组件所需模块
  4. class MyForms(forms.Form):
  5. # username字符串类型最小3位最大8位
  6. username = forms.CharField(max_length=8,min_length=3,label="用户名")
  7. # password字符串类型最小3位最大8位
  8. password = forms.CharField(max_length=8,min_length=3,label="密码")
  9. # email字段必须符合邮箱格式 xxx@xx.com
  10. email = forms.EmailField(label="邮箱")
  11. # 校验数据
  12. def ab_form(request):
  13. # 1 先产生一个空对象
  14. form_obj = MyForms()
  15. if request.method == "POST":
  16. # 获取用户数据
  17. """
  18. 1.数据获取繁琐
  19. 2.校验数据需要构造成字典的格式传入才行
  20. ps:但是request.POST可以看成就是一个字典
  21. """
  22. # 3.校验数据
  23. form_obj = MyForms(request.POST) # 注意这里变量名一定要和产生的空对象的变量名一致
  24. # 4.判断数据是否合法
  25. if form_obj.is_valid():
  26. # 5.如果合法 操作数据库存储数据
  27. return HttpResponse('OK')
  28. # 5.不合法 在前端通过forms对象errors结合errors展示错误信息
  29. return render(request,"ab_form.html",locals())

注意:

  1. """
  2. 1.必备的条件 get请求和post传给html页面对象变量名必须一样
  3. 2.forms组件当你的数据不合法的情况下 会保存你上次的数据 让你基于之前的结果进行修改
  4. 更加的人性化
  5. """

ab_form.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. <!-- Bootstrap3 核心 CSS 文件 -->
  7. <link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
  8. <!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
  9. <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
  10. <!-- Bootstrap3 核心 JavaScript 文件 -->
  11. <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
  12. <!-- font-awesome.min.css图标库4.7版本 -->
  13. <link href="https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
  14. </head>
  15. <body>
  16. <div class="container-fluid">
  17. <div class="row">
  18. <div class="col-md-8 col-md-offset-2">
  19. <form action="" method="post" novalidate>
  20. {% for form in form_obj %}
  21. <p>
  22. {{ form.label }}:{{ form }}
  23. <span style="color: red">{{ form.errors }}</span>
  24. </p>
  25. {% endfor %}
  26. <input type="submit" class="btn btn-info">
  27. </form>
  28. </div>
  29. </div>
  30. </div>
  31. </body>
  32. </html>

浏览器输入不符合校验的数据

Django之forms组件 - 图6

注意:这个提示信息是浏览器自动帮你校验的

  1. """
  2. 浏览器会自动帮你校验数据 但是前端的校验弱不禁风
  3. 如何让浏览器不做校验
  4. <form action="" method="post" novalidate>
  5. """

关闭浏览器自动校验以及注意事项

  1. <form action="" method="post" novalidate>
  2. {% for form in form_obj %}
  3. <p>
  4. {{ form.label }}:{{ form }}
  5. <span style="color: red">{{ form.errors }}</span>
  6. </p>
  7. {% endfor %}
  8. <input type="submit" class="btn btn-info">
  9. </form>

发现错误信息是以li标签展示的

Django之forms组件 - 图7

标准姿势:form.errors.0:只拿列表第一个错误信息

  1. <form action="" method="post" novalidate>
  2. {% for form in form_obj %}
  3. <p>
  4. {{ form.label }}:{{ form }}
  5. <span style="color: red">{{ form.errors.0 }}</span>
  6. </p>
  7. {% endfor %}
  8. <input type="submit" class="btn btn-info">
  9. </form>

Django之forms组件 - 图8

错误提示信息默认为英文,可以自定义,看下面自定义错误提示信息。

自定义错误提示信息

字段的添加error_messages={“错误条件”:”错误信息”,”错误条件”:”错误信息”…}

  1. # 针对错误的提示信息还可以自己自定制
  2. class MyForm(forms.Form):
  3. # username字符串类型最小3位最大8位
  4. username = forms.CharField(min_length=3,max_length=8,label='用户名',
  5. error_messages={
  6. 'min_length':'用户名最少3位',
  7. 'max_length':'用户名最大8位',
  8. 'required':"用户名不能为空"
  9. }
  10. )
  11. # password字符串类型最小3位最大8位
  12. password = forms.CharField(min_length=3,max_length=8,label='密码',
  13. error_messages={
  14. 'min_length': '密码最少3位',
  15. 'max_length': '密码最大8位',
  16. 'required': "密码不能为空"
  17. }
  18. )
  19. # email字段必须符合邮箱格式 xxx@xx.com
  20. email = forms.EmailField(label='邮箱',
  21. error_messages={
  22. 'invalid':'邮箱格式不正确',
  23. 'required': "邮箱不能为空"
  24. }
  25. )

forms组件钩子函数(HOOK)

  1. """
  2. 在特定的节点自动触发完成响应操作
  3. 钩子函数在forms组件中就类似于第二道关卡,能够让我们自定义校验规则
  4. 在forms组件中有两类钩子
  5. 1.局部钩子
  6. 当你需要给单个字段增加校验规则的时候可以使用
  7. 2.全局钩子
  8. 当你需要给多个字段增加校验规则的时候可以使用
  9. """

实际案例

需求:

  1. # 1.校验用户名中不能含有666 只是校验username字段 局部钩子
  2. # 2.校验密码和确认密码是否一致 password confirm两个字段 全局钩子

urls.py

  1. from django.conf.urls import url
  2. from django.contrib import admin
  3. from app01 import views
  4. urlpatterns = [
  5. url(r'^admin/', admin.site.urls),
  6. # forms组件
  7. url(r'^ab_form/', views.ab_form),
  8. ]
  9. urls.py

views.py

  1. from django.shortcuts import render,HttpResponse
  2. # 基本使用
  3. from django import forms # forms组件所需模块
  4. class MyForms(forms.Form):
  5. # username字符串类型最小3位最大8位
  6. username = forms.CharField(max_length=8,min_length=3,label="用户名",
  7. error_messages={
  8. 'min_length':'用户名最少3位',
  9. 'max_length':'用户名最大8位',
  10. 'required':"用户名不能为空"
  11. }
  12. )
  13. # password字符串类型最小3位最大8位
  14. password = forms.CharField(max_length=8,min_length=3,label="密码",
  15. error_messages = {
  16. 'min_length': '密码最少3位',
  17. 'max_length': '密码最大8位',
  18. 'required': "密码不能为空"
  19. }
  20. )
  21. re_password = forms.CharField(max_length=8, min_length=3, label="确认密码",
  22. error_messages={
  23. 'min_length': '确认密码最少3位',
  24. 'max_length': '确认密码最大8位',
  25. 'required': "确认密码不能为空"
  26. }
  27. )
  28. # email字段必须符合邮箱格式 xxx@xx.com
  29. email = forms.EmailField(label="邮箱",
  30. error_messages={
  31. 'invalid': '邮箱格式不正确',
  32. 'required': "邮箱不能为空"
  33. }
  34. )
  35. # 钩子函数
  36. # 局部钩子
  37. def clean_username(self): # 用来校验username,走这一步前提是上面username字段条件满足了
  38. # 获取到用户名
  39. username = self.cleaned_data.get("username")
  40. if '666' in username:
  41. # 提示前端展示报错信息
  42. self.add_error("username","用户名不合法") # 添加一个错误信息,第一个参数是给哪个字段增加错误信息,第二个参数是错误信息内容
  43. # 将钩子函数钩取到的数据再放回去
  44. return username
  45. # 全局钩子
  46. def clean(self): # 全局钩子
  47. password = self.cleaned_data.get("password")
  48. re_password = self.cleaned_data.get("re_password")
  49. if not password == re_password:
  50. self.add_error("re_password","两次密码不一致")
  51. # 将钩子函数钩取的数据返回
  52. return self.cleaned_data
  53. # 校验数据
  54. def ab_form(request):
  55. # 1 先产生一个空对象
  56. form_obj = MyForms()
  57. if request.method == "POST":
  58. # 获取用户数据
  59. """
  60. 1.数据获取繁琐
  61. 2.校验数据需要构造成字典的格式传入才行
  62. ps:但是request.POST可以看成就是一个字典
  63. """
  64. # 3.校验数据
  65. form_obj = MyForms(request.POST)
  66. # 4.判断数据是否合法
  67. if form_obj.is_valid():
  68. # 5.如果合法 操作数据库存储数据
  69. return HttpResponse('OK')
  70. # 5.不合法 有错误
  71. return render(request,"ab_form.html",locals())

ab_form.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. <!-- Bootstrap3 核心 CSS 文件 -->
  7. <link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
  8. <!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
  9. <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
  10. <!-- Bootstrap3 核心 JavaScript 文件 -->
  11. <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
  12. <!-- font-awesome.min.css图标库4.7版本 -->
  13. <link href="https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
  14. </head>
  15. <body>
  16. <div class="container-fluid">
  17. <div class="row">
  18. <div class="col-md-8 col-md-offset-2">
  19. <form action="" method="post" novalidate>
  20. {% for form in form_obj %}
  21. <p>
  22. {{ form.label }}:{{ form }}
  23. <span style="color: red">{{ form.errors.0 }}</span>
  24. </p>
  25. {% endfor %}
  26. <input type="submit" class="btn btn-info">
  27. </form>
  28. </div>
  29. </div>
  30. </div>
  31. </body>
  32. </html>

效果:

Django之forms组件 - 图9

forms组件字段的其他参数及补充知识点

forms类中常见字段

  1. max_length # 允许输入的最大长度
  2. min_length # 最小长度
  3. label # input的提示信息,name、password等
  4. error_messages # 自定义报错的提示信息
  5. initial # 设置默认值
  6. required # 控制字段是否必填
  7. widget # 控制type类型及属性

字段样式以及正则参数:

  1. """
  2. 1.字段没有样式
  3. 2.针对不同类型的input如何修改
  4. text
  5. password
  6. date
  7. radio
  8. checkbox
  9. ...
  10. """
  11. # 可以通过为字段添加wiget参数进行设置,属性多个值用空格隔开
  12. widget=forms.widgets.标签类型(attrs={'class':'form-control c1 c2'})
  13. # 多个属性值的话 直接空格隔开即可
  14. # 字段里面还有支持正则校验的参数,注意要导入正则匹配的组件
  15. from django.core.validators import RegexValidator # 导入正则匹配组件
  16. validators=[
  17. RegexValidator(r'^[0-9]+$', '请输入数字'),
  18. RegexValidator(r'^159[0-9]+$', '数字必须以159开头')
  19. ]

案例:提示报错信息时,文本框也会变红

views.py

  1. from django.shortcuts import render,HttpResponse
  2. from app01 import models
  3. # 基本使用
  4. from django import forms # forms组件所需模块
  5. from django.core.validators import RegexValidator # 导入正则匹配的组件
  6. class MyForms(forms.Form):
  7. # username字符串类型最小3位最大8位
  8. username = forms.CharField(max_length=8,min_length=3,label="用户名",
  9. error_messages={
  10. 'min_length':'用户名最少3位',
  11. 'max_length':'用户名最大8位',
  12. 'required':"用户名不能为空"
  13. },
  14. widget=forms.widgets.TextInput(attrs={'class':'form-control'})
  15. )
  16. # password字符串类型最小3位最大8位
  17. password = forms.CharField(max_length=8,min_length=3,label="密码",
  18. error_messages = {
  19. 'min_length': '密码最少3位',
  20. 'max_length': '密码最大8位',
  21. 'required': "密码不能为空"
  22. },
  23. widget=forms.widgets.PasswordInput(attrs={'class':'form-control'})
  24. )
  25. re_password = forms.CharField(max_length=8, min_length=3, label="确认密码",
  26. error_messages={
  27. 'min_length': '确认密码最少3位',
  28. 'max_length': '确认密码最大8位',
  29. 'required': "确认密码不能为空"
  30. },
  31. widget=forms.widgets.PasswordInput(attrs={'class':'form-control'})
  32. )
  33. phone =forms.CharField(max_length=11, min_length=11, label="手机号",
  34. error_messages={
  35. 'min_length': '手机号最少11位',
  36. 'max_length': '手机号最大11位',
  37. 'required': "手机号不能为空"
  38. },
  39. widget=forms.widgets.TextInput(attrs={'class':'form-control'}),
  40. validators=[
  41. RegexValidator(r'^[0-9]+$', '请输入数字'),
  42. RegexValidator(r'^159[0-9]+$', '数字必须以159开头')
  43. ]
  44. )
  45. # email字段必须符合邮箱格式 xxx@xx.com
  46. email = forms.EmailField(label="邮箱",
  47. error_messages={
  48. 'invalid': '邮箱格式不正确',
  49. 'required': "邮箱不能为空"
  50. },
  51. widget=forms.widgets.EmailInput(attrs={'class':'form-control'})
  52. )
  53. # 钩子函数
  54. # 局部钩子
  55. def clean_username(self): # 用来校验username,走这一步前提是上面username字段条件满足了
  56. # 获取到用户名
  57. username = self.cleaned_data.get("username")
  58. # 判断用户是否存在
  59. user_obj = models.User.objects.filter(username=username).first()
  60. if user_obj:
  61. self.add_error("username","用户已存在")
  62. # if '666' in username:
  63. # 提示前端展示报错信息
  64. # 方法一:add_error()
  65. # self.add_error("username","用户名不合法") # 添加一个错误信息,第一个参数是给哪个字段增加错误信息,第二个参数是错误信息内容
  66. # 方法二:主动抛出异常raise 需要导入ValidationError, from django.core.exceptions import ValidationError
  67. # raise ValidationError("用户名不合法")
  68. # 将钩子函数钩取到的数据再放回去
  69. return username
  70. # 全局钩子
  71. def clean(self): # 全局钩子
  72. password = self.cleaned_data.get("password")
  73. re_password = self.cleaned_data.get("re_password")
  74. if not password == re_password:
  75. self.add_error("re_password","两次密码不一致")
  76. # 将钩子函数钩取的数据返回
  77. return self.cleaned_data
  78. # 校验数据
  79. def ab_form(request):
  80. # 1 先产生一个空对象
  81. form_obj = MyForms()
  82. if request.method == "POST":
  83. # 获取用户数据
  84. """
  85. 1.数据获取繁琐
  86. 2.校验数据需要构造成字典的格式传入才行
  87. ps:但是request.POST可以看成就是一个字典
  88. """
  89. # 3.校验数据
  90. form_obj = MyForms(request.POST)
  91. # 4.判断数据是否合法
  92. if form_obj.is_valid():
  93. # 5.如果合法 操作数据库存储数据
  94. return HttpResponse('OK')
  95. # 5.不合法 有错误
  96. return render(request,"ab_form.html",locals())
  97. views.py

ab_form.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. <!-- Bootstrap3 核心 CSS 文件 -->
  7. <link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
  8. <!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
  9. <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
  10. <!-- Bootstrap3 核心 JavaScript 文件 -->
  11. <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
  12. <!-- font-awesome.min.css图标库4.7版本 -->
  13. <link href="https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
  14. </head>
  15. <body>
  16. <div class="container-fluid">
  17. <div class="row">
  18. <div class="col-md-8 col-md-offset-2">
  19. <form action="" method="post" novalidate>
  20. {% for form in form_obj %}
  21. <p>
  22. {{ form.label }}:{{ form }}
  23. <span style="color: red" class="input_span">{{ form.errors.0 }}</span>
  24. </p>
  25. {% endfor %}
  26. <p>
  27. 性别:<input type="radio" name="gender" value="1" checked>
  28. <input type="radio" name="gender" value="2">
  29. <input type="radio" name="gender" value="3"> 保密
  30. </p>
  31. <input type="submit" class="btn btn-info btn-block" id="btn">
  32. </form>
  33. </div>
  34. </div>
  35. </div>
  36. <script>
  37. $("p span").each(function(){
  38. if($(this).text()){
  39. $(this).prev().css("border","solid red")
  40. }
  41. });
  42. </script>
  43. </body>
  44. </html>
  45. ab_form.html

效果

Django之forms组件 - 图10

其他类型渲染

  1. # radio 单选按钮
  2. gender = forms.ChoiceField(
  3. choices=((1, "男"), (2, "女"), (3, "保密")),
  4. label="性别",
  5. initial=3,
  6. widget=forms.widgets.RadioSelect()
  7. )
  8. # select
  9. hobby = forms.ChoiceField(
  10. choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
  11. label="爱好",
  12. initial=3,
  13. widget=forms.widgets.Select()
  14. )
  15. # 多选
  16. hobby1 = forms.MultipleChoiceField(
  17. choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
  18. label="爱好",
  19. initial=[1, 3],
  20. widget=forms.widgets.SelectMultiple()
  21. )
  22. # 单选checkbox
  23. keep = forms.ChoiceField(
  24. label="是否记住密码",
  25. initial="checked",
  26. widget=forms.widgets.CheckboxInput()
  27. )
  28. # 多选checkbox
  29. hobby2 = forms.MultipleChoiceField(
  30. choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
  31. label="爱好",
  32. initial=[1, 3],
  33. widget=forms.widgets.CheckboxSelectMultiple()
  34. )

forms组件源码

  1. """
  2. 切入点:
  3. form_obj.is_valid()
  4. """
  5. def is_valid(self):
  6. """
  7. Returns True if the form has no errors. Otherwise, False. If errors are
  8. being ignored, returns False.
  9. """
  10. return self.is_bound and not self.errors
  11. # 如果is_valid要返回True的话 那么self.is_bound要为True self.errors要为Flase
  12. self.is_bound = data is not None or files is not None # 只要你传值了肯定为True
  13. @property
  14. def errors(self):
  15. "Returns an ErrorDict for the data provided for the form"
  16. if self._errors is None:
  17. self.full_clean()
  18. return self._errors
  19. # forms组件所有的功能基本都出自于该方法
  20. def full_clean(self):
  21. self._clean_fields() # 校验字段 + 局部钩子
  22. self._clean_form() # 全局钩子
  23. self._post_clean()

源码大体执行流程

  1. # forms组件源码执行流程
  2. form.is_valid()----》内部起了一个for循环,先去校验每个字段配置的规则,校验完成,走该字段的局部钩子函数,一个一个执行完(交验完)---》会走全局钩子(clean())--->self就会有clean_dataerrors
  3. 1 流程:
  4. 1 form.is_valid()
  5. 2 self.errors
  6. 3 self.full_clean()
  7. 4 self._clean_fields() 局部字段的校验(自己的和局部钩子)
  8. if hasattr(self, 'clean_%s' % name):
  9. func=getattr(self, 'clean_%s' % name)
  10. value = func()
  11. self.cleaned_data[name] = value
  12. self._clean_form() 全局的钩子
  13. self._post_clean()

看源码知道使用钩子函数要提示前端展示报错信息还有一种通过raise主动抛出一次的方法(针对局部钩子):不过不推荐

示例:(看局部钩子函数部分)

views.py

  1. from django.shortcuts import render,HttpResponse
  2. from django.core.exceptions import ValidationError
  3. # 基本使用
  4. from django import forms # forms组件所需模块
  5. from django.core.validators import RegexValidator # 导入正则匹配的组件
  6. class MyForms(forms.Form):
  7. # username字符串类型最小3位最大8位
  8. username = forms.CharField(max_length=8,min_length=3,label="用户名",
  9. error_messages={
  10. 'min_length':'用户名最少3位',
  11. 'max_length':'用户名最大8位',
  12. 'required':"用户名不能为空"
  13. },
  14. widget=forms.widgets.TextInput(attrs={'class':'form-control'})
  15. )
  16. # password字符串类型最小3位最大8位
  17. password = forms.CharField(max_length=8,min_length=3,label="密码",
  18. error_messages = {
  19. 'min_length': '密码最少3位',
  20. 'max_length': '密码最大8位',
  21. 'required': "密码不能为空"
  22. },
  23. widget=forms.widgets.PasswordInput(attrs={'class':'form-control'})
  24. )
  25. re_password = forms.CharField(max_length=8, min_length=3, label="确认密码",
  26. error_messages={
  27. 'min_length': '确认密码最少3位',
  28. 'max_length': '确认密码最大8位',
  29. 'required': "确认密码不能为空"
  30. },
  31. widget=forms.widgets.PasswordInput(attrs={'class':'form-control'})
  32. )
  33. phone =forms.CharField(max_length=11, min_length=11, label="手机号",
  34. error_messages={
  35. 'min_length': '手机号最少11位',
  36. 'max_length': '手机号最大11位',
  37. 'required': "手机号不能为空"
  38. },
  39. widget=forms.widgets.TextInput(attrs={'class':'form-control'}),
  40. validators=[
  41. RegexValidator(r'^[0-9]+$', '请输入数字'),
  42. RegexValidator(r'^159[0-9]+$', '数字必须以159开头')
  43. ]
  44. )
  45. # email字段必须符合邮箱格式 xxx@xx.com
  46. email = forms.EmailField(label="邮箱",
  47. error_messages={
  48. 'invalid': '邮箱格式不正确',
  49. 'required': "邮箱不能为空"
  50. },
  51. widget=forms.widgets.EmailInput(attrs={'class':'form-control'})
  52. )
  53. # 钩子函数
  54. # 局部钩子
  55. def clean_username(self): # 用来校验username,走这一步前提是上面username字段条件满足了
  56. # 获取到用户名
  57. username = self.cleaned_data.get("username")
  58. if '666' in username:
  59. # 提示前端展示报错信息
  60. # 方法一:add_error(),推荐使用
  61. # self.add_error("username","用户名不合法") # 添加一个错误信息,第一个参数是给哪个字段增加错误信息,第二个参数是错误信息内容
  62. # 方法二:(不推荐使用)主动抛出异常raise 需要导入ValidationError, from django.core.exceptions import ValidationError
  63. raise ValidationError("用户名不合法")
  64. # 将钩子函数钩取到的数据再放回去
  65. return username
  66. # 全局钩子
  67. def clean(self): # 全局钩子
  68. password = self.cleaned_data.get("password")
  69. re_password = self.cleaned_data.get("re_password")
  70. if not password == re_password:
  71. self.add_error("re_password","两次密码不一致")
  72. # 将钩子函数钩取的数据返回
  73. return self.cleaned_data
  74. # 校验数据
  75. def ab_form(request):
  76. # 1 先产生一个空对象
  77. form_obj = MyForms()
  78. if request.method == "POST":
  79. # 获取用户数据
  80. """
  81. 1.数据获取繁琐
  82. 2.校验数据需要构造成字典的格式传入才行
  83. ps:但是request.POST可以看成就是一个字典
  84. """
  85. print(request.POST)
  86. # 3.校验数据
  87. form_obj = MyForms(request.POST)
  88. # 4.判断数据是否合法
  89. if form_obj.is_valid():
  90. # 5.如果合法 操作数据库存储数据
  91. return HttpResponse('OK')
  92. # 5.不合法 有错误
  93. return render(request,"ab_form.html",locals())