Django框架

Form介绍 

我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来。

与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否输入,输入的长度和格式等正不正确。如果用户输入的内容有错误就需要在页面上相应的位置显示显示对应的错误信息.。

Django form组件就实现了上面所述的功能。

总结一下,Form组件可以做的几件事情:

  1、用户请求数据验证

  2、自动生成错误信息    

  3、打包用户提交的正确信息

  4、如果其中有一个错误了,其他的正确这,保留上次输入的内容

  4、自动创建input标签并可以设置样式

二、Form组件的使用

  1、创建规则

1class Foo(Form): #必须继承 2 username = xxx 3 password = xxx 4 email = xxx 5注意这里的字段必须和input的name字段一致

  2、数据和规则进行匹配

 先导入view.py

1from django.forms import Form 2from django.forms import fields 3from django.forms import widgets 4 5from django.shortcuts import render,redirect 6from app01 import models 7# Create your views here. 8from django.forms import Form 9from django.forms import fields 10from django.forms import widgets 11# 1、创建规则 12class TeacherForm(Form): #必须继承Form 13 # 创建字段,本质上是正则表达式 14 username = fields.CharField( 15 required=True, #必填字段 16 error_messages={"required":"用户名不能为空!!"}, #显示中文错误提示 17 widget=widgets.TextInput(attrs={"placeholder":"用户名","class":"form-control"}) #自动生成input框 18 ) 19 password = fields.CharField(required=True, error_messages={'required': '密码不能为空'}, 20 widget=widgets.TextInput(attrs={'placeholder': '密码', 'class': 'form-control'})) # 不能为空 21 email = fields.EmailField( 22 required=True, 23 error_messages={"required":"邮箱不能为空!!","invalid":"无效的邮箱"}, 24 widget=widgets.EmailInput(attrs={"placeholder": "邮箱", "class": "form-control"}) # 自动生成input框 25 ) #不能为空且邮箱格式要一致 26 27# 2、使用规则:将数据和规则进行匹配 28def teacherindex(request): 29 teacher_obj = models.UserInfo.objects.all() 30 # print(teacher_obj) 31 return render(request,"teacherindex.html",{"teacher_obj":teacher_obj}) 32def add(request): 33 if request.method=="GET": 34 form = TeacherForm() #只是让显示一个input框 35 return render(request,"add.html",{"form":form }) 36 else: 37 form = TeacherForm(data=request.POST) 38 # print(form) #<QuerySet [<UserInfo: UserInfo object>, <UserInfo: UserInfo object>, <UserInfo: UserInfo object>]> 39 if form.is_valid():# 开始验证 40 # print('执行成功',form.cleaned_data) # 所有匹配成功,字典 41 # {'username': 'asd', 'password': 'sdf', 'email': 'sadf@live.com','ut_id':1} 42 form.cleaned_data['ut_id'] = 1 #要分的清是班主任还是讲师 43 models.UserInfo.objects.all().create(**form.cleaned_data) 44 return redirect("/teacherindex/") 45 else: 46 # print("=====?",form.errors,type(form.errors))#返回失败的结果 47 # print(form.errors["username"][0]) #拿到返回失败的结果,渲染到页面 48 return render(request,"add.html",{"form":form})

html.py

1{% block right %} 2 <h1>添加老师信息</h1> 3 <hr> 4 <form method="post" novalidate> 5 {% csrf_token %} 6 <p>姓名:{{ form.username }}</p>{{ form.errors.username.0 }} 7 <p>密码:{{ form.password }}</p>{{ form.errors.password.0 }} 8 <p>邮箱:{{ form.email }}</p>{{ form.errors.email.0 }} 9 <p><input type="submit" value="提交"></p> 10 </form> 11{% 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

       吧班主任和老师可以放到一个表中、因为他们有相同的属性,如果属性全是一样的,可以放在一个表里(推荐)

     也可以分开放,老师表是老师表,班主任表是班主任表。这样就会进行连表操作,连表有性能消耗。

举例:文章和文章类型

   分析:一个文章有一个类型,一个类型可以对应多个文章(所以文章和文章类型是一对多的关系,关联字段要放在多的一方)

  一:连表设计:

1class News(models.Model): 2 title = models.CharField(max_length=32) 3 summary = models.CharField(max_length=255) 4 news_type = models.ForeignKey(to="NewsType") 5class NewsType(models.Model): 6 type_title = models.CharField(max_length=32) 7 8News:

  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

1class News2(models.Model): 2 title = models.CharField(max_length=32) 3 summary = models.CharField(max_length=255) 4 news_type_chices = ( 5 (1, '图片'), 6 (4, '挨踢1024'), 7 (3, '段子'), 8 ) 9 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() )

举例二:用户和用户类型

  一:连表设计

1class UserType(models.Model): 2 """ 3 用户类型表,个数经常变动 4 """ 5 title = models.CharField(max_length=32) 6 7class UserInfo(models.Model): 8 """ 9 用户表:讲师和班主任 10 """ 11 username = models.CharField(max_length=32) 12 password = models.CharField(max_length=64) 13 email = models.CharField(max_length=32) 14 ut = models.ForeignKey(to="UserType")

  二:不连表设计:choices

1class UserInfo(models.Model): 2# """ 3# 用户表 4# """ 5 username = models.CharField(max_length=32) 6 password = models.CharField(max_length=64) 7 email = models.CharField(max_length=32,verbose_name="邮箱") 8 user_type_choices = ( 9 (1, '班主任'), 10 (2, '讲师'), 11 ) 12 13 user_type_id = models.IntegerField(choices=user_type_choices)

四、登录

 可设置一个装饰器

1def auth(func): 2 def inner(request,*args,**kwargs): 3 is_login = request.session.get("is_login", None) 4 if not is_login: 5 return redirect("/login/") 6 ret = func(*args,**kwargs) 7 return ret 8 return inner

 需要注意的:  

  1、action不写路径,默认提交到当前 

  2、向后台提交数据用post,获取数据用get

  3、submit一般加上value,有些浏览器可能会不识别

  4、一般配置文件的键都是大写的

 实例

普通的登录

views.py

1def login(request): 2 error_msg = "" 3 if request.method == "POST": 4 username = request.POST.get("username") 5 pwd = request.POST.get("pwd") 6 if username == "Q1mi" and pwd == "123456": 7 return HttpResponse("OK") 8 else: 9 error_msg = "用户名或密码错误" 10 return render(request, "login.html", {"error_msg": error_msg})

login.html

1<!DOCTYPE html> 2<html lang="en"> 3<head> 4 <meta charset="UTF-8"> 5 <meta http-equiv="x-ua-compatible" content="IE=edge"> 6 <meta name="viewport" content="width=device-width, initial-scale=1"> 7 <title>login</title> 8 <style> 9 .error { 10 color: red; 11 } 12 </style> 13</head> 14<body> 15<form action="/login/" method="post"> 16 {% csrf_token %} 17 <p> 18 <label for="username">用户名</label> 19 <input type="text" name="username" id="username"> 20 </p> 21 <p> 22 <label for="pwd">密码</label> 23 <input type="password" name="pwd" id="pwd"> 24 <span class="error"></span> 25 </p> 26 <p> 27 <input type="submit"> 28 <span class="error">{{ error_msg }}</span> 29 </p> 30</form> 31</body> 32</html>

使用form组件

views.py

先定义好一个LoginForm类。

1class LoginForm(forms.Form): 2 username = forms.CharField(min_length=8, label="用户名") 3 pwd = forms.CharField(min_length=6, label="密码") 4 5 6def login2(request): 7 error_msg = "" 8 form_obj = LoginForm() 9 if request.method == "POST": 10 form_obj = LoginForm(request.POST) 11 if form_obj.is_valid(): 12 username = form_obj.cleaned_data.get("username") 13 pwd = form_obj.cleaned_data.get("pwd") 14 if username == "Q1mi" and pwd == "123456": 15 return HttpResponse("OK") 16 else: 17 error_msg = "用户名或密码错误" 18 return render(request, "login2.html", {"form_obj": form_obj, "error_msg": error_msg})

login2.html

1<!DOCTYPE html> 2<html lang="en"> 3<head> 4 <meta charset="UTF-8"> 5 <meta http-equiv="x-ua-compatible" content="IE=edge"> 6 <meta name="viewport" content="width=device-width, initial-scale=1"> 7 <title>login</title> 8 <style> 9 .error { 10 color: red; 11 } 12 </style> 13</head> 14<body> 15<form action="/login2/" method="post" novalidate> 16 {% csrf_token %} 17 <p> 18 {{ form_obj.username.label }} 19 {{ form_obj.username }} 20 <span class="error">{{ form_obj.username.errors.0 }}</span> 21 </p> 22 <p> 23 {{ form_obj.pwd.label }} 24 {{ form_obj.pwd }} 25 <span class="error">{{ form_obj.pwd.errors.0 }}</span> 26 </p> 27 <p> 28 <input type="submit"> 29 <span class="error">{{ error_msg }}</span> 30 </p> 31</form> 32</body> 33</html>

看网页效果发现 也验证了form的功能:
• 前端页面是form类的对象生成的                                      -->生成HTML标签功能
• 当用户名和密码输入为空或输错之后 页面都会提示        -->用户提交校验功能
• 当用户输错之后 再次输入 上次的内容还保留在input框   -->保留上次输入内容

Form那些事儿

常用字段演示

initial

初始值,input框里面的初始值。

1class LoginForm(forms.Form): 2 username = forms.CharField( 3 min_length=8, 4 label="用户名", 5 initial="张三" # 设置默认值 6 ) 7 pwd = forms.CharField(min_length=6, label="密码")

error_messages

重写错误信息。

1class LoginForm(forms.Form): 2 username = forms.CharField( 3 min_length=8, 4 label="用户名", 5 initial="张三", 6 error_messages={ 7 "required": "不能为空", 8 "invalid": "格式错误", 9 "min_length": "用户名最短8位" 10 } 11 ) 12 pwd = forms.CharField(min_length=6, label="密码")

password

1class LoginForm(forms.Form): 2 ... 3 pwd = forms.CharField( 4 min_length=6, 5 label="密码", 6 widget=forms.widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True) 7 )

radioSelect

单radio值为字符串

1class LoginForm(forms.Form): 2 username = forms.CharField( 3 min_length=8, 4 label="用户名", 5 initial="张三", 6 error_messages={ 7 "required": "不能为空", 8 "invalid": "格式错误", 9 "min_length": "用户名最短8位" 10 } 11 ) 12 pwd = forms.CharField(min_length=6, label="密码") 13 gender = forms.fields.ChoiceField( 14 choices=((1, "男"), (2, "女"), (3, "保密")), 15 label="性别", 16 initial=3, 17 widget=forms.widgets.RadioSelect 18 )

单选Select

1class LoginForm(forms.Form): 2 ... 3 hobby = forms.fields.ChoiceField( 4 choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ), 5 label="爱好", 6 initial=3, 7 widget=forms.widgets.Select 8 )

多选Select

1class LoginForm(forms.Form): 2 ... 3 hobby = forms.fields.MultipleChoiceField( 4 choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ), 5 label="爱好", 6 initial=[1, 3], 7 widget=forms.widgets.SelectMultiple 8 )

单选checkbox

1class LoginForm(forms.Form): 2 ... 3 keep = forms.fields.ChoiceField( 4 label="是否记住密码", 5 initial="checked", 6 widget=forms.widgets.CheckboxInput 7 )

多选checkbox

1class LoginForm(forms.Form): 2 ... 3 hobby = forms.fields.MultipleChoiceField( 4 choices=((1, "篮球"), (2, "足球"), (3, "双色球"),), 5 label="爱好", 6 initial=[1, 3], 7 widget=forms.widgets.CheckboxSelectMultiple 8 )

关于choice的注意事项:

在使用选择标签时,需要注意choices的选项可以从数据库中获取,但是由于是静态字段 ***获取的值无法实时更新***,那么需要自定义构造方法从而达到此目的。

方式一:

1from django.forms import Form 2from django.forms import widgets 3from django.forms import fields 4 5 6class MyForm(Form): 7 8 user = fields.ChoiceField( 9 # choices=((1, '上海'), (2, '北京'),), 10 initial=2, 11 widget=widgets.Select 12 ) 13 14 def __init__(self, *args, **kwargs): 15 super(MyForm,self).__init__(*args, **kwargs) 16 # self.fields['user'].widget.choices = ((1, '上海'), (2, '北京'),) 17 # 或 18 self.fields['user'].widget.choices = models.Classes.objects.all().values_list('id','caption')

方式二:

1from django import forms 2from django.forms import fields 3from django.forms import models as form_model 4 5 6class FInfo(forms.Form): 7 authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all()) 8 # authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all())

校验

方式一:

1from django.forms import Form 2from django.forms import widgets 3from django.forms import fields 4from django.core.validators import RegexValidator 5 6class MyForm(Form): 7 user = fields.CharField( 8 validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')], 9 )

方式二:

1import re 2from django.forms import Form 3from django.forms import widgets 4from django.forms import fields 5from django.core.exceptions import ValidationError 6 7 8# 自定义验证规则 9def mobile_validate(value): 10 mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$') 11 if not mobile_re.match(value): 12 raise ValidationError('手机号码格式错误') 13 14 15class PublishForm(Form): 16 17 18 title = fields.CharField(max_length=20, 19 min_length=5, 20 error_messages={'required': '标题不能为空', 21 'min_length': '标题最少为5个字符', 22 'max_length': '标题最多为20个字符'}, 23 widget=widgets.TextInput(attrs={'class': "form-control", 24 'placeholder': '标题5-20个字符'})) 25 26 27 # 使用自定义验证规则 28 phone = fields.CharField(validators=[mobile_validate, ], 29 error_messages={'required': '手机不能为空'}, 30 widget=widgets.TextInput(attrs={'class': "form-control", 31 'placeholder': u'手机号码'})) 32 33 email = fields.EmailField(required=False, 34 error_messages={'required': u'邮箱不能为空','invalid': u'邮箱格式错误'}, 35 widget=widgets.TextInput(attrs={'class': "form-control", 'placeholder': u'邮箱'}))

补充进阶

应用Bootstrap样式

1<!DOCTYPE html> 2<html lang="en"> 3<head> 4 <meta charset="UTF-8"> 5 <meta http-equiv="x-ua-compatible" content="IE=edge"> 6 <meta name="viewport" content="width=device-width, initial-scale=1"> 7 <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css"> 8 <title>login</title> 9</head> 10<body> 11<div class="container"> 12 <div class="row"> 13 <form action="/login2/" method="post" novalidate class="form-horizontal"> 14 {% csrf_token %} 15 <div class="form-group"> 16 <label for="{{ form_obj.username.id_for_label }}" 17 class="col-md-2 control-label">{{ form_obj.username.label }}</label> 18 <div class="col-md-10"> 19 {{ form_obj.username }} 20 <span class="help-block">{{ form_obj.username.errors.0 }}</span> 21 </div> 22 </div> 23 <div class="form-group"> 24 <label for="{{ form_obj.pwd.id_for_label }}" class="col-md-2 control-label">{{ form_obj.pwd.label }}</label> 25 <div class="col-md-10"> 26 {{ form_obj.pwd }} 27 <span class="help-block">{{ form_obj.pwd.errors.0 }}</span> 28 </div> 29 </div> 30 <div class="form-group"> 31 <label class="col-md-2 control-label">{{ form_obj.gender.label }}</label> 32 <div class="col-md-10"> 33 <div class="radio"> 34 {% for radio in form_obj.gender %} 35 <label for="{{ radio.id_for_label }}"> 36 {{ radio.tag }}{{ radio.choice_label }} 37 </label> 38 {% endfor %} 39 </div> 40 </div> 41 </div> 42 <div class="form-group"> 43 <div class="col-md-offset-2 col-md-10"> 44 <button type="submit" class="btn btn-default">注册</button> 45 </div> 46 </div> 47 </form> 48 </div> 49</div> 50 51<script src="/static/jquery-3.2.1.min.js"></script> 52<script src="/static/bootstrap/js/bootstrap.min.js"></script> 53</body> 54</html>

Django form应用Bootstrap样式简单示例

批量添加样式

可通过重写form类的init方法来实现。

1class LoginForm(forms.Form): 2 username = forms.CharField( 3 min_length=8, 4 label="用户名", 5 initial="张三", 6 error_messages={ 7 "required": "不能为空", 8 "invalid": "格式错误", 9 "min_length": "用户名最短8位" 10 } 11 ... 12 13 def __init__(self, *args, **kwargs): 14 super(LoginForm, self).__init__(*args, **kwargs) 15 for field in iter(self.fields): 16 self.fields[field].widget.attrs.update({ 17 'class': 'form-control' 18 })

批量添加样式

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

jango Form表单组件

Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来。与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否输入,输入的长度和格式等正不正确。如果用户输入的内容有错误就需要在页面上相应的位置显示对应的错误信息.。Djangoform组件就实

Django框架 - HelloWorld