Django框架----Form组件
Form介绍
我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来。
与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否输入,输入的长度和格式等正不正确。如果用户输入的内容有错误就需要在页面上相应的位置显示显示对应的错误信息.。
Django form组件就实现了上面所述的功能。
总结一下,Form组件可以做的几件事情:
1、用户请求数据验证
2、自动生成错误信息
3、打包用户提交的正确信息
4、如果其中有一个错误了,其他的正确这,保留上次输入的内容
4、自动创建input标签并可以设置样式
二、Form组件的使用
1、创建规则
- class Foo(Form): #必须继承
- username = xxx
- password = xxx
- email = xxx
- 注意这里的字段必须和input的name字段一致
2、数据和规则进行匹配
先导入view.py
- from django.forms import Form
- from django.forms import fields
- from django.forms import widgets
- from django.shortcuts import render,redirect
- from app01 import models
- # Create your views here.
- from django.forms import Form
- from django.forms import fields
- from django.forms import widgets
- # 1、创建规则
- class TeacherForm(Form): #必须继承Form
- # 创建字段,本质上是正则表达式
- username = fields.CharField(
- required=True, #必填字段
- error_messages={"required":"用户名不能为空!!"}, #显示中文错误提示
- widget=widgets.TextInput(attrs={"placeholder":"用户名","class":"form-control"}) #自动生成input框
- )
- password = fields.CharField(required=True, error_messages={'required': '密码不能为空'},
- widget=widgets.TextInput(attrs={'placeholder': '密码', 'class': 'form-control'})) # 不能为空
- email = fields.EmailField(
- required=True,
- error_messages={"required":"邮箱不能为空!!","invalid":"无效的邮箱"},
- widget=widgets.EmailInput(attrs={"placeholder": "邮箱", "class": "form-control"}) # 自动生成input框
- ) #不能为空且邮箱格式要一致
- # 2、使用规则:将数据和规则进行匹配
- def teacherindex(request):
- teacher_obj = models.UserInfo.objects.all()
- # print(teacher_obj)
- return render(request,"teacherindex.html",{"teacher_obj":teacher_obj})
- def add(request):
- if request.method=="GET":
- form = TeacherForm() #只是让显示一个input框
- return render(request,"add.html",{"form":form })
- else:
- form = TeacherForm(data=request.POST)
- # print(form) #<QuerySet [<UserInfo: UserInfo object>, <UserInfo: UserInfo object>, <UserInfo: UserInfo object>]>
- if form.is_valid():# 开始验证
- # print('执行成功',form.cleaned_data) # 所有匹配成功,字典
- # {'username': 'asd', 'password': 'sdf', 'email': 'sadf@live.com','ut_id':1}
- form.cleaned_data['ut_id'] = 1 #要分的清是班主任还是讲师
- models.UserInfo.objects.all().create(**form.cleaned_data)
- return redirect("/teacherindex/")
- else:
- # print("=====?",form.errors,type(form.errors))#返回失败的结果
- # print(form.errors["username"][0]) #拿到返回失败的结果,渲染到页面
- return render(request,"add.html",{"form":form})
html.py
- {% block right %}
- <h1>添加老师信息</h1>
- <hr>
- <form method="post" novalidate>
- {% csrf_token %}
- <p>姓名:{{ form.username }}</p>{{ form.errors.username.0 }}
- <p>密码:{{ form.password }}</p>{{ form.errors.password.0 }}
- <p>邮箱:{{ form.email }}</p>{{ form.errors.email.0 }}
- <p><input type="submit" value="提交"></p>
- </form>
- {% endblock %}
如果访问视图的是一个GET
请求,它将创建一个空的表单实例并将它放置到要渲染的模板的上下文中。这是我们在第一个访问该URL 时预期发生的情况。
如果表单的提交使用POST
请求,那么视图将再次创建一个表单实例并使用请求中的数据填充它:form = NameForm(request.POST)
。这叫做”绑定数据至表单“(它现在是一个绑定的表单)。
我们调用表单的is_valid()
方法;如果它不为True
,我们将带着这个表单返回到模板。这时表单不再为空(未绑定),所以HTML 表单将用之前提交的数据填充,然后可以根据要求编辑并改正它。
如果is_valid()
为True
,我们将能够在cleaned_data
属性中找到所有合法的表单数据。在发送HTTP 重定向给浏览器告诉它下一步的去向之前,我们可以用这个数据来更新数据库或者做其它处理。
注意: form = TeacherForm() #没有参数,只是一个input框
form = TeacherForm(data=request.POST) # 数据和规则放置一起 (添加的时候用)
form = TeacherForm(initial={'username':obj.username,'password':obj.password,'email':obj.email}) # 显示input,并且将数据库中的默认值填写到input框中 (编辑的时候用)
Widgets
每个表单字段都有一个对应的Widget
类,它对应一个HTML 表单Widget
,例如<input type="text">
。
在大部分情况下,字段都具有一个合理的默认Widget。例如,默认情况下,CharField
具有一个TextInput Widget
,它在HTML 中生成一个<input type="text">
。
字段的数据
不管表单提交的是什么数据,一旦通过调用is_valid()
成功验证(is_valid()
返回True
),验证后的表单数据将位于form.cleaned_data
字典中。这些数据已经为你转换好为Python 的类型。
注:此时,你依然可以从request.POST
中直接访问到未验证的数据,但是访问验证后的数据更好一些。
在上面的联系表单示例中,is_married将是一个布尔值。类似地,IntegerField
和FloatField
字段分别将值转换为Python 的int
和float
。
三、数据库表设计
设计表时注意的几点:
1、 nid = models.AutoField(primary_key=True) #如果不指定django会默认加上id的
nid = models.BigAutoField(primary_key=True) #但那些整型满足不了你的时候,就用BigAutoField
2、对于类的注释一般加在类里面
3、verbose_name=“标题” 字段的中文提示
4、ForeignKey(to = "表名",tofield= "字段") #这两个to可以不用写,但是关联的表名一定要写
5、releated_name = "uuu" 反向查询。如果一个表中有多个ManyTwoMany()或者ForeignKey()必须加上releated_name
6、字段经常变动的适合连表
字段变化小,不怎么变的适合在一个表中,不进行连表:就用choices
吧班主任和老师可以放到一个表中、因为他们有相同的属性,如果属性全是一样的,可以放在一个表里(推荐)
也可以分开放,老师表是老师表,班主任表是班主任表。这样就会进行连表操作,连表有性能消耗。
举例:文章和文章类型
分析:一个文章有一个类型,一个类型可以对应多个文章(所以文章和文章类型是一对多的关系,关联字段要放在多的一方)
一:连表设计:
- class News(models.Model):
- title = models.CharField(max_length=32)
- summary = models.CharField(max_length=255)
- news_type = models.ForeignKey(to="NewsType")
- class NewsType(models.Model):
- type_title = models.CharField(max_length=32)
- News:
id title summary news_type_id
1 t.... 科技... 2
2 t.... 科技... 1
3 t.... 科技... 2
- NewsType:
id title
1 图片
2 挨踢1024
3 段子
# 查看所有新闻
new_list = models.News.objects.all()
for row in new_list:
print(row.title,row.summary,row.news_type.title)
二 :放在一个表中的操作:choices
- class News2(models.Model):
- title = models.CharField(max_length=32)
- summary = models.CharField(max_length=255)
- news_type_chices = (
- (1, '图片'),
- (4, '挨踢1024'),
- (3, '段子'),
- )
- news_type = models.IntegerField(choices=news_type_chices)
# 查看所有新闻
new_list = News.objects.all()
for row in new_list:
print(row.title,row.summary, row.get_news_type_display() )
举例二:用户和用户类型
一:连表设计
- class UserType(models.Model):
- """
- 用户类型表,个数经常变动
- """
- title = models.CharField(max_length=32)
- class UserInfo(models.Model):
- """
- 用户表:讲师和班主任
- """
- username = models.CharField(max_length=32)
- password = models.CharField(max_length=64)
- email = models.CharField(max_length=32)
- ut = models.ForeignKey(to="UserType")
二:不连表设计:choices
- class UserInfo(models.Model):
- # """
- # 用户表
- # """
- username = models.CharField(max_length=32)
- password = models.CharField(max_length=64)
- email = models.CharField(max_length=32,verbose_name="邮箱")
- user_type_choices = (
- (1, '班主任'),
- (2, '讲师'),
- )
- user_type_id = models.IntegerField(choices=user_type_choices)
四、登录
可设置一个装饰器
- def auth(func):
- def inner(request,*args,**kwargs):
- is_login = request.session.get("is_login", None)
- if not is_login:
- return redirect("/login/")
- ret = func(*args,**kwargs)
- return ret
- return inner
需要注意的:
1、action不写路径,默认提交到当前
2、向后台提交数据用post,获取数据用get
3、submit一般加上value,有些浏览器可能会不识别
4、一般配置文件的键都是大写的
实例
普通的登录
views.py
- def login(request):
- error_msg = ""
- if request.method == "POST":
- username = request.POST.get("username")
- pwd = request.POST.get("pwd")
- if username == "Q1mi" and pwd == "123456":
- return HttpResponse("OK")
- else:
- error_msg = "用户名或密码错误"
- return render(request, "login.html", {"error_msg": error_msg})
login.html
- <!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>login</title>
- <style>
- .error {
- color: red;
- }
- </style>
- </head>
- <body>
- <form action="/login/" method="post">
- {% csrf_token %}
- <p>
- <label for="username">用户名</label>
- <input type="text" name="username" id="username">
- </p>
- <p>
- <label for="pwd">密码</label>
- <input type="password" name="pwd" id="pwd">
- <span class="error"></span>
- </p>
- <p>
- <input type="submit">
- <span class="error">{{ error_msg }}</span>
- </p>
- </form>
- </body>
- </html>
使用form组件
views.py
先定义好一个LoginForm类。
- class LoginForm(forms.Form):
- username = forms.CharField(min_length=8, label="用户名")
- pwd = forms.CharField(min_length=6, label="密码")
- def login2(request):
- error_msg = ""
- form_obj = LoginForm()
- if request.method == "POST":
- form_obj = LoginForm(request.POST)
- if form_obj.is_valid():
- username = form_obj.cleaned_data.get("username")
- pwd = form_obj.cleaned_data.get("pwd")
- if username == "Q1mi" and pwd == "123456":
- return HttpResponse("OK")
- else:
- error_msg = "用户名或密码错误"
- return render(request, "login2.html", {"form_obj": form_obj, "error_msg": error_msg})
login2.html
- <!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>login</title>
- <style>
- .error {
- color: red;
- }
- </style>
- </head>
- <body>
- <form action="/login2/" method="post" novalidate>
- {% csrf_token %}
- <p>
- {{ form_obj.username.label }}
- {{ form_obj.username }}
- <span class="error">{{ form_obj.username.errors.0 }}</span>
- </p>
- <p>
- {{ form_obj.pwd.label }}
- {{ form_obj.pwd }}
- <span class="error">{{ form_obj.pwd.errors.0 }}</span>
- </p>
- <p>
- <input type="submit">
- <span class="error">{{ error_msg }}</span>
- </p>
- </form>
- </body>
- </html>
看网页效果发现 也验证了form的功能:
• 前端页面是form类的对象生成的 -->生成HTML标签功能
• 当用户名和密码输入为空或输错之后 页面都会提示 -->用户提交校验功能
• 当用户输错之后 再次输入 上次的内容还保留在input框 -->保留上次输入内容
Form那些事儿
常用字段演示
initial
初始值,input框里面的初始值。
- class LoginForm(forms.Form):
- username = forms.CharField(
- min_length=8,
- label="用户名",
- initial="张三" # 设置默认值
- )
- pwd = forms.CharField(min_length=6, label="密码")
error_messages
重写错误信息。
- class LoginForm(forms.Form):
- username = forms.CharField(
- min_length=8,
- label="用户名",
- initial="张三",
- error_messages={
- "required": "不能为空",
- "invalid": "格式错误",
- "min_length": "用户名最短8位"
- }
- )
- pwd = forms.CharField(min_length=6, label="密码")
password
- class LoginForm(forms.Form):
- ...
- pwd = forms.CharField(
- min_length=6,
- label="密码",
- widget=forms.widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True)
- )
radioSelect
单radio值为字符串
- class LoginForm(forms.Form):
- username = forms.CharField(
- min_length=8,
- label="用户名",
- initial="张三",
- error_messages={
- "required": "不能为空",
- "invalid": "格式错误",
- "min_length": "用户名最短8位"
- }
- )
- pwd = forms.CharField(min_length=6, label="密码")
- gender = forms.fields.ChoiceField(
- choices=((1, "男"), (2, "女"), (3, "保密")),
- label="性别",
- initial=3,
- widget=forms.widgets.RadioSelect
- )
单选Select
- class LoginForm(forms.Form):
- ...
- hobby = forms.fields.ChoiceField(
- choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
- label="爱好",
- initial=3,
- widget=forms.widgets.Select
- )
多选Select
- class LoginForm(forms.Form):
- ...
- hobby = forms.fields.MultipleChoiceField(
- choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
- label="爱好",
- initial=[1, 3],
- widget=forms.widgets.SelectMultiple
- )
单选checkbox
- class LoginForm(forms.Form):
- ...
- keep = forms.fields.ChoiceField(
- label="是否记住密码",
- initial="checked",
- widget=forms.widgets.CheckboxInput
- )
多选checkbox
- class LoginForm(forms.Form):
- ...
- hobby = forms.fields.MultipleChoiceField(
- choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
- label="爱好",
- initial=[1, 3],
- widget=forms.widgets.CheckboxSelectMultiple
- )
关于choice的注意事项:
在使用选择标签时,需要注意choices的选项可以从数据库中获取,但是由于是静态字段 ***获取的值无法实时更新***,那么需要自定义构造方法从而达到此目的。
方式一:
- from django.forms import Form
- from django.forms import widgets
- from django.forms import fields
- class MyForm(Form):
- user = fields.ChoiceField(
- # choices=((1, '上海'), (2, '北京'),),
- initial=2,
- widget=widgets.Select
- )
- def __init__(self, *args, **kwargs):
- super(MyForm,self).__init__(*args, **kwargs)
- # self.fields['user'].widget.choices = ((1, '上海'), (2, '北京'),)
- # 或
- self.fields['user'].widget.choices = models.Classes.objects.all().values_list('id','caption')
方式二:
- from django import forms
- from django.forms import fields
- from django.forms import models as form_model
- class FInfo(forms.Form):
- authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all())
- # authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all())
校验
方式一:
- from django.forms import Form
- from django.forms import widgets
- from django.forms import fields
- from django.core.validators import RegexValidator
- class MyForm(Form):
- user = fields.CharField(
- validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
- )
方式二:
- import re
- from django.forms import Form
- from django.forms import widgets
- from django.forms import fields
- from django.core.exceptions import ValidationError
- # 自定义验证规则
- def mobile_validate(value):
- mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
- if not mobile_re.match(value):
- raise ValidationError('手机号码格式错误')
- class PublishForm(Form):
- title = fields.CharField(max_length=20,
- min_length=5,
- error_messages={'required': '标题不能为空',
- 'min_length': '标题最少为5个字符',
- 'max_length': '标题最多为20个字符'},
- widget=widgets.TextInput(attrs={'class': "form-control",
- 'placeholder': '标题5-20个字符'}))
- # 使用自定义验证规则
- phone = fields.CharField(validators=[mobile_validate, ],
- error_messages={'required': '手机不能为空'},
- widget=widgets.TextInput(attrs={'class': "form-control",
- 'placeholder': u'手机号码'}))
- email = fields.EmailField(required=False,
- error_messages={'required': u'邮箱不能为空','invalid': u'邮箱格式错误'},
- widget=widgets.TextInput(attrs={'class': "form-control", 'placeholder': u'邮箱'}))
补充进阶
应用Bootstrap样式
- <!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>login</title>
- </head>
- <body>
- <div class="container">
- <div class="row">
- <form action="/login2/" method="post" novalidate class="form-horizontal">
- {% csrf_token %}
- <div class="form-group">
- <label for="{{ form_obj.username.id_for_label }}"
- class="col-md-2 control-label">{{ form_obj.username.label }}</label>
- <div class="col-md-10">
- {{ form_obj.username }}
- <span class="help-block">{{ form_obj.username.errors.0 }}</span>
- </div>
- </div>
- <div class="form-group">
- <label for="{{ form_obj.pwd.id_for_label }}" class="col-md-2 control-label">{{ form_obj.pwd.label }}</label>
- <div class="col-md-10">
- {{ form_obj.pwd }}
- <span class="help-block">{{ form_obj.pwd.errors.0 }}</span>
- </div>
- </div>
- <div class="form-group">
- <label class="col-md-2 control-label">{{ form_obj.gender.label }}</label>
- <div class="col-md-10">
- <div class="radio">
- {% for radio in form_obj.gender %}
- <label for="{{ radio.id_for_label }}">
- {{ radio.tag }}{{ radio.choice_label }}
- </label>
- {% endfor %}
- </div>
- </div>
- </div>
- <div class="form-group">
- <div class="col-md-offset-2 col-md-10">
- <button type="submit" class="btn btn-default">注册</button>
- </div>
- </div>
- </form>
- </div>
- </div>
- <script src="/static/jquery-3.2.1.min.js"></script>
- <script src="/static/bootstrap/js/bootstrap.min.js"></script>
- </body>
- </html>
Django form应用Bootstrap样式简单示例
批量添加样式
可通过重写form类的init方法来实现。
- class LoginForm(forms.Form):
- username = forms.CharField(
- min_length=8,
- label="用户名",
- initial="张三",
- error_messages={
- "required": "不能为空",
- "invalid": "格式错误",
- "min_length": "用户名最短8位"
- }
- ...
- def __init__(self, *args, **kwargs):
- super(LoginForm, self).__init__(*args, **kwargs)
- for field in iter(self.fields):
- self.fields[field].widget.attrs.update({
- 'class': 'form-control'
- })
批量添加样式
Django框架----Form组件的更多相关文章
- Django 框架 Form组件
一.Form组件简介 Form组件是django中一个非常强大的组件,在处理服务端和前端的交互上大大的提高了开发人员的开发速度. Form组件的功能: 用于处理前后端的数据认证(显示错误信息) 用于生 ...
- Django框架----Form组件补充
一.Form类 创建Form类时,主要涉及到 [字段] 和 [插件],字段用于对用户请求数据的验证,插件用于自动生成HTML; 1.Django内置字段如下: 1 Field 2 required=T ...
- python框架之Django(10)-Form组件
介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来.与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否输入,输入 ...
- Django之Form组件
Django之Form组件 本节内容 基本使用 form中字段和插件 自定义验证规则 动态加载数据到form中 1. 基本使用 django中的Form组件有以下几个功能: 生成HTML标签 验证用户 ...
- Python之路【第二十一篇】:Django之Form组件
Django之Form组件 Django的Form主要具有一下几大功能: 生成HTML标签 验证用户数据(显示错误信息) HTML Form提交保留上次提交数据 初始化页面显示内容 小试牛刀 1. ...
- 第十一篇:web之Django之Form组件
Django之Form组件 Django之Form组件 本节内容 基本使用 form中字段和插件 自定义验证规则 动态加载数据到form中 1. 基本使用 django中的Form组件有以下几个功 ...
- python Django之Form组件
python Django之Form组件 Django的Form主要具有一下几大功能: 生成HTML标签 验证用户数据(显示错误信息) HTML Form提交保留上次提交数据 初始化页面显示内容 小试 ...
- Django之Form组件(一)
Django之Form组件(一) Django的Form主要具有一下几大功能: 生成HTML标签 验证用户数据(显示错误信息) HTML Form提交保留上次提交数据 初始化页面显示内容 基本操作:字 ...
- 〖Python〗-- Django的Form组件
[Django的Form组件] Django的Form主要具有一下几大功能: 生成HTML标签 验证用户数据(显示错误信息) HTML Form提交保留上次提交数据 初始化页面显示内容 Form类的使 ...
随机推荐
- C# List去重的三种方法
三种去重的方法 1.List中的元素实现IEquatabe接口,并提供Equals方法和GetHashCode方法. 2.使用表达式 users.Where((x,i)=>users.FindI ...
- vue-router路由管理器
安装vue-router npm install vue-router 在main.js中引入 import VueRouter from 'vue-router' Vue.use(VueRouter ...
- linux下禁止root远程登录和添加新用户
https://www.cnblogs.com/jianz/p/7979250.html 一.添加和root权限一样的用户 1. adduser admin passwd admin (修改密码) ...
- [vue]data数据属性及ref获取dom
data项的定义 this.$refs获取dom 获取不到数据 这样中转下才ok 小结: data里不能用this.$ref. 另外使用visjs时候 view-source:http://visjs ...
- vue的图片路径,和背景图片路径打包后错误解决
最近在研究vue,老实的按照官网提供的,搭建的了 webpack+vue+vuex+vue-router,,因为是自己搭建的,所以踩了不少坑,一般问题百度都有,这个背景图片的问题,查了很久才解决. 1 ...
- vue2.0--请求数据
vue中用vue-reouse请求来的数据,会被封装一层,如下图res:
- python使用cx_Oracle在Linux和Windows下的一点差异
1. 主要是线程方面的差异. Windows下,把cx_Oracle.connect(connectedId)得到的handle传给定时器线程,主线程和和定时器可以用同一个handle. 但Linux ...
- vmware相关设置
vmware虚拟机和宿主机共享文件夹 点击“虚拟机”->“设置” 进入之后,选择“选项”选项卡->选择“共享文件夹”(此处已启用实在安装VMware Tools时选择了启用共享文件夹功能) ...
- android js与控件交互初探。
1.创建一个mainacvity 在oncreate中加入, mWeb是一个webview组件,网络权限记得自己加. <uses-permission android:name="an ...
- 前端获取的数据是undefined
var id = $("id1").val(); var username = $("username1").val(); var password = $(& ...