Form组件 (什么是form组件?为什么要用rorm组件?怎么用form组件?)
第一大功能:对用户请求的验证--->只要用户提交数据就可以用它来验证。
第二大功能:生成HTML代码
前端发送请求,后台得到前端发送的内容,如果要存到数据库中需要对传过来的数据做验证,返回页面的时候,如果有错误需要在页面上展示出来。
要求: 1.检查是否为空 2.检查格式是否正确
比如: 对用户名的要求不能为空,长度在6-8之间 对密码的要求不能为空,必须字母数字,长度必须大于8位 对邮箱的要求不能为空,必须是邮箱格式 对年龄的要求不能为空,必须是整数类型
我们要做的是
模板层怎么提交数据
视图层怎么获取数据,怎么校验数据
校验完数据后
1、我们需要将正确的如果写入数据库
2、我们将验证时出现的错误信息在提交的页面上显示出来
Form组件校验字段功能
第一步:创建一个类。创建类必须引入和继承下面写的
from django import forms class MyForm(forms.Form):
第二步:类中创建字段(包含正则表达式)。必须引入下面写的
from django import forms from django.forms import fields class MyForm(forms.Form): user = fields.CharField(max_length=20,min_length=1,required=True)
以上的意思是创建了一个类,写了一些字段,字段相应的设置了一些约束条件。最长18,最短1,不能为空。
用它定制的规则来验证用户发送的请求。把有用的信息提取出来才能进行操作。对应关系是:前端的input标签的name等于个什么就对应这里写的MyForm里面的字段名等于什么。比如前端在name是email的input标签里输入的值,就会与MyForm类的email字段里的规则进行比对。
models模型层
urls路由层
views视图层
获取前端传过来的数据
ORM操作
写入数据库可以是一个字段一个字段对应的写,还可以传一个字典
templates模板层
form表单和ajax都能向后端提交数据。
区别:
form提交是直接刷新页面,ajax是页面局部刷新。

<!-- form表单提交数据, id是可以通过id值来找到这个form表单,然后进行相关操作 action填写请求的url, method填请求的方式, input标签, id是可以通过id值来找到这个input标签,然后进行相关操作 type是input输入框输 name填写的值就是后端获取input输入内容的键,用过它可以获取input提交的内容 --> <form id="fm" action="/add_user/" method="post"> {% csrf_token %} <div> <label for="name">用户名:</label> <input type="text" name="name" id="name"> </div> <div> <label for="pwd">密码:</label> <input type="password" name="pwd" id="pwd"> </div> <div> <label for="email">邮箱:</label> <input type="text" name="email" id="email"> </div> <input type="submit" value="form提交"> <input id="ajax_Btn" type="button" value="ajax提交"> </form> <!-- ajax 需要引入jquery文件 需要给ajax提交按钮绑定事件让它去提交数据 如何获取标签里的数据这里要用到JavaScript的知识 --> <script src="/static/jquery.js"></script> <script> $('#ajax_Btn').on('click',function () { $.ajax({ url:'/add_user/', type:'post', //serialize()方法是获取 data:$('#fm').serialize(), success:function (data) { //对后台返回的数据的具体操作 console.log(data); }, }) }) </script>
检验字段功能的代码:

from django.shortcuts import render,redirect from django import forms from django.forms import fields class MyForm(forms.Form): name = fields.CharField(max_length=20,min_length=1,required=True) pwd = fields.CharField(max_length=16,min_length=6,required=True) age = fields.IntegerField(required=True) email = fields.EmailField(required=True)
渲染错误信息功能

<div> <label for="name">用户名:</label> <input type="text" name="name" id="name"><span>{{ errors_Msg.name }}</span> </div> <div> <label for="pwd">密码:</label> <input type="password" name="pwd" id="pwd">{{ errors_Msg.pwd }} </div> <div> <label for="age">年龄:</label> <input type="text" name="age" id="age">{{ errors_Msg.age }} </div> <div> <label for="email">邮箱:</label> <input type="email" name="email" id="email">{{ errors_Msg.email }} </div> <input type="submit" value="form提交"> {# <input id="ajax_Btn" type="button" value="ajax提交">#} </form>
出现这种情况是因为一个输入框可能同时出现两个错误。
解决方法就是我们只取错误提示的第一个。

<div> <label for="name">用户名:</label> <input type="text" name="name" id="name"><span>{{ errors_Msg.name.0 }}</span> </div> <div> <label for="pwd">密码:</label> <input type="password" name="pwd" id="pwd">{{ errors_Msg.pwd.0 }} </div> <div> <label for="age">年龄:</label> <input type="text" name="age" id="age">{{ errors_Msg.age.0 }} </div> <div> <label for="email">邮箱:</label> <input type="email" name="email" id="email">{{ errors_Msg.email.0 }} </div> <input type="submit" value="form提交"> {# <input id="ajax_Btn" type="button" value="ajax提交">#} </form>
如果改成中文

from django.shortcuts import render,redirect from django import forms from django.forms import fields class MyForm(forms.Form): name = fields.CharField( max_length=20, min_length=1, required=True, error_messages={ 'required':'不能为空', 'min_length':'太短了', 'max_length':'太长了', } ) pwd = fields.CharField( max_length=16, min_length=6, required=True, error_messages={ 'required': '不能为空', 'min_length': '太短了', 'max_length': '太长了', } ) age = fields.IntegerField( required=True, error_messages={ 'required':'不能为空', # 所有遇到格式错误的都叫invalid 'invalid':'格式错误' } ) email = fields.EmailField( required=True, error_messages={ 'required':'不能为空', 'invalid':'格式错误' } )
渲染标签(HTML)功能
协同开发,前端写HTML,后端写form。可能写的字段和前端的name属性对应不起来。怎么解决?
那就前端不要写了。在什么条件下生成HTML代码?
在GET请求时,创建一个MyForm的对象,这个对象可以点出来类里面的属性。所以把这个对象也传到前端。在前端可以这么写
def add_user(request): if request.method == 'GET': from_obj = MyForm() return render(request,'add_user.html',{'form_obj':from_obj})
在前端可以这么写
<form id="fm" action="/add_user/" method="post"> {% csrf_token %} <div> {{ form_obj.name }}{{ errors_Msg.name.0 }} </div> <div> {{ form_obj.pwd }}{{ errors_Msg.pwd.0 }} </div> <div> {{ form_obj.age }}{{ errors_Msg.age.0 }} </div> <div> {{ form_obj.email }}{{ errors_Msg.email.0 }} </div> <input type="submit" value="form提交"> </form>
案例:
客户通过url来访问网站展示用户信息
通过添加按钮来添加用户,用form组件生成HTMLinput标签,get请求展示添加页面,并且进行字段校验,post请求如果前端填写的不正确要返回填写的内容以及错误信息。如果通过校验则写入数据库并且重新展示客户信息页面。
通过编辑操作来修改当前客户的信息,还是要求用form组件生成HTML标签,get请求时要根据用户的id获取当前用户的信息,然后到编辑页面并把用户信息在页面展示出来。如果是post请求还需要进行字段校验,校验成功更新,校验失败返回错误的提示。

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css"> <title>Title</title> </head> <body> <a href="/add_user/">增加用户</a> <div class="bs-example" data-example-id="bordered-table"> <table class="table table-bordered table-hover"> <thead> <tr> <th>id</th> <th>用户名</th> <th>邮箱</th> <th>操作</th> </tr> </thead> <tbody> {% for user in user_list %} <tr> <td>{{ user.id }}</td> <td>{{ user.username }}</td> <td>{{ user.email }}</td> {# <td><a href="/edit_user/?nid={{ user.id }}">编辑</a></td>#} <td><a href="/edit_user-{{ user.id }}/">编辑</a></td> </tr> {% endfor %} </tbody> </table> </div> </body> </html>

<form id="fm" action="/add_user/" method="post" novalidate> {% csrf_token %} <div> <label for=""> 用户名</label> {{ form_obj.username }}{{ form_obj.errors.username.0 }} </div> <div> <label for=""> 邮箱</label> {{ form_obj.email }}{{ form_obj.errors.email.0 }} </div> <input type="submit" value="form提交"> </form>

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> </head> <body> <form action="/edit_user-{{ nid }}/" method="post" novalidate> {% csrf_token %} <div> <label for=""> 用户名</label> {{ form_obj.username }}{{ form_obj.errors.username.0 }} </div> <div> <label for=""> 邮箱</label> {{ form_obj.email }}{{ form_obj.errors.email.0 }} </div> <input type="submit" value="提交"> </form> </body> </html>

from django import forms from django.forms import fields class MyForm(forms.Form): username = fields.CharField( max_length=20, min_length=2, required=True, error_messages={ 'max_length': '太长了', 'min_length': '太短了', 'required': '不能为空', 'invalid': '格式不正确' }) email = fields.EmailField( required=True, error_messages={ 'required': '必须填写邮箱', 'invalid': '格式填写错误' } )

from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^users/', views.users), url(r'^add_user/', views.add_user), url(r'^edit_user-(d+)/', views.edit_user), ]

from django.shortcuts import render,redirect from app01 import models from app01.myforms import MyForm def users(request): if request.method == 'GET': user_list = models.UserInfo.objects.all() return render(request,'userInfo.html',{'user_list':user_list}) elif request.method == 'POST': # return redirect('/get_userInfo/') return redirect('https://www.baidu.com') def add_user(request): if request.method == 'GET': from_obj = MyForm() return render(request,'add_user.html',{'form_obj':from_obj}) elif request.method == 'POST': # 数据与规则进行比对 # 会自动去取前端的请求,比较完了之后产生一个结果,如果错误有错误信息,如果正确了会将正确数据给你。 form_obj = MyForm(request.POST) if form_obj.is_valid(): models.UserInfo.objects.create(**form_obj.cleaned_data) return redirect('/users/') else: print('验证失败',form_obj.errors) return render(request,'add_user.html',{'form_obj':form_obj}) def edit_user(request,nid): if request.method == 'GET': # 从数据库拿数据到前端渲染 user_data = models.UserInfo.objects.filter(id=nid).first() form_obj = MyForm({'username':user_data.username,'email':user_data.email}) return render(request,'edit_user.html',{'form_obj':form_obj,'nid':nid}) elif request.method == 'POST': form_obj = MyForm(request.POST) if form_obj.is_valid(): models.UserInfo.objects.filter(id=nid).update(**form_obj.cleaned_data) return redirect('/users/') else: return render(request, 'edit_user.html',{'form_obj':form_obj,'nid':nid})
相关的mysql数据库配置、数据库表设计我们这里就不展示了。但是用form组件来生成HTML标签一定要注意对应关系,from的字段必须和input标签的对应。
form字段
创建Form类时,主要涉及到 【字段】 和 【插件】,字段用于对用户请求数据的验证,插件用于自动生成HTML;
我们自己写的类的字段它继承了Field:也就是django内置的字段
1 Field 2 required=True, 是否允许为空 3 widget=None, HTML插件 4 label=None, 用于生成Label标签或显示内容 5 initial=None, 初始值 6 help_text='', 帮助信息(在标签旁边显示) 7 error_messages=None, 错误信息 {'required': '不能为空', 'invalid': '格式错误'} 8 show_hidden_initial=False, 是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直) 9 validators=[], 自定义验证规则 10 localize=False, 是否支持本地化 11 disabled=False, 是否可以编辑 12 label_suffix=None Label内容后缀
如果字段是CharField格式里面常用的参数有:
- required:True 不允许为空
- max_length=18 最大长度为18
- min_length=2 最小长度为2
- strip:True 移除用户输入的空白
如果字段是IntegerField格式里面常用的参数
- min_value=0 最小值
- max_value=110 最大值
DecimalField(IntegerField) max_value=None, 最大值 min_value=None, 最小值 max_digits=None, 总长度 decimal_places=None, 小数位长度
DateField(BaseTemporalField) 格式:2015-09-01
DateTimeField(BaseTemporalField)格式:2015-09-01 11:12
FileField(Field)
allow_empty_file=False 是否允许空文件
ImageField(FileField) ... 注:需要PIL模块,pip3 install Pillow 以上两个字典使用时,需要注意两点: - form表单中 enctype="multipart/form-data" - view函数中 obj = MyForm(request.POST, request.FILES)
ChoiceField(Field) ... choices=(), 选项,如:choices = ((0,'上海'),(1,'北京'),) required=True, 是否必填 widget=None, 插件,默认select插件 label=None, Label内容 initial=None, 初始值 help_text='', 帮助提示
多选框
MultipleChoiceField(ChoiceField)
字符串转换成int类型
TypedChoiceField(ChoiceField) coerce = lambda val: val 对选中的值进行一次转换 empty_value= '' 空值的默认值
TypedMultipleChoiceField(MultipleChoiceField) coerce = lambda val: val 对选中的每一个值进行一次转换 empty_value= '' 空值的默认值
GenericIPAddressField protocol='both', both,ipv4,ipv6支持的IP格式 unpack_ipv4=False 解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用

from django import forms from django.forms import fields from django.forms import widgets class UserForm(forms.Form): user = fields.CharField( max_length=20, min_length=2, required=True, label='用户名:', initial='请输入用户名', error_messages={ 'max_length': '太长了', 'min_length': '太短了', 'required': '不能为空', } ) age = fields.IntegerField( required=True, min_value=0, max_value=110, label='年龄:', error_messages={ 'max_value': '年龄太大了', 'min_value': '年龄太小了', 'required': '不能为空', } ) email = fields.EmailField( label='邮箱:', initial='请填写你的邮箱', ) file = fields.FileField( label='文件:', ) # ChoiceField生成下拉框 city = fields.ChoiceField( label='城市:', choices=[(1, 'beijing'), (2, 'nanjing'), (3, 'shanghai')], initial=3, # 默认选择3上海 ) hobby = fields.MultipleChoiceField( label='爱好', choices=[(1, 'read'), (2, 'music'), (3, 'traveling'), (4, 'swimming')], #设置默认值,列表 initial=[1,2] )
form插件
插件的作用是自定义生成HTML标签,在每个插件里面可以给当前生成的这个标签自定义属性,属性叫attrs。
如果是对于特殊的下拉框对它的select或者是有这种数据源的东西的时候,我们用choices。
django内置的插件
1 TextInput(Input) 2 NumberInput(TextInput) 3 EmailInput(TextInput) 4 URLInput(TextInput) 5 PasswordInput(TextInput) 6 HiddenInput(TextInput) 7 Textarea(Widget) 8 DateInput(DateTimeBaseInput) 9 DateTimeInput(DateTimeBaseInput) 10 TimeInput(DateTimeBaseInput) 11 CheckboxInput 12 Select 13 NullBooleanSelect 14 SelectMultiple 15 RadioSelect 16 CheckboxSelectMultiple 17 FileInput 18 ClearableFileInput 19 MultipleHiddenInput 20 SplitDateTimeWidget 21 SplitHiddenDateTimeWidget 22 SelectDateWidget
常用插件:
# 单radio,值为字符串 # user = fields.CharField( # initial=2, # widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),)) # ) # 单radio,值为字符串 # user = fields.ChoiceField( # choices=((1, '上海'), (2, '北京'),), # initial=2, # widget=widgets.RadioSelect # ) # 单select,值为字符串 # user = fields.CharField( # initial=2, # widget=widgets.Select(choices=((1,'上海'),(2,'北京'),)) # ) # 单select,值为字符串 # user = fields.ChoiceField( # choices=((1, '上海'), (2, '北京'),), # initial=2, # widget=widgets.Select # ) # 多选select,值为列表 # user = fields.MultipleChoiceField( # choices=((1,'上海'),(2,'北京'),), # initial=[1,], # widget=widgets.SelectMultiple # ) # 单checkbox # user = fields.CharField( # widget=widgets.CheckboxInput() # ) # 多选checkbox,值为列表 # user = fields.MultipleChoiceField( # initial=[2, ], # choices=((1, '上海'), (2, '北京'),), # widget=widgets.CheckboxSelectMultiple # )
数据源无法时时更新,有两种方法
方式一:重构构造方法(推荐)
方法一:重构构造方法(推荐) class ClassesForm(Form): name = fields.CharField( required=True, # 必填字段 error_messages={"required": "姓名不能为空!!"}, # 显示中文错误提示 widget=widgets.TextInput(attrs={"placeholder": "姓名", "class": "form-control"}), # 自动生成input框 ) # 如果直接定义成classteacher_id,,_id 的形式,这样你添加数据的时候不会时时更新,所以在下面定义一个重写的方法 # classteacher_id = fields.ChoiceField(choices= models.UserInfo.objects.filter(ut_id = settings.ROLE_CLASSTEACHER).values_list('id', "username")) classteacher_id = fields.ChoiceField(choices=[]) def __init__(self,*args,**kwargs): #重写init方法,时时更新 super().__init__(*args,**kwargs) #继承父类 self.fields["classteacher_id"].choices = models.UserInfo.objects.filter(ut_id = settings.ROLE_CLASSTEACHER).values_list('id', "username") 注意: 要是这样:fields.ChoiceField(choices=[]) 注意choices里面传[(1,"讲师"),(2,"班主任"),(3,"管理员")]所以数据库里取的时候得用values_list
Form基本使用
类 字段 is_valid() cleaned_data errors 字段参数: max_length min_length validators = [RegexValidators("xxx")] 钩子函数 clean_字段名 注意: 必须有返回值 只能拿自己当前字段值 raise ValidationError("xxx") 下拉框数据源时时更新 1、重写init方法 先执行父类构造方法 self.fields["xx"].choices = xxxxx 2、ModelChoiceField
end