我们前面都是手工在HTML文件中编写表单form元素,然后在views.py的视图函数中接收表单中的用户数据,再编写验证代码进行验证,最后使用ORM进行数据库的增删改查。这样费时费力,整个过程比较复杂,而且有可能写得不太恰当,数据验证也比较麻烦。

设想一下,如果我们的表单拥有几十上百个数据字段,有不同的数据特点,如果也使用手工的方式,其效率和正确性都将无法得到保障。

有鉴于此,Django在内部集成了一个表单功能,以面向对象的方式,直接使用Python代码生成HTML表单代码,专门帮助我们快速处理表单相关的内容。

Django的表单给我们提供了下面三个主要功能:

  • 准备和重构数据用于页面渲染;
  • 为数据创建HTML表单元素;
  • 接收和处理用户从表单发送过来的数据。

编写Django的form表单,非常类似我们在模型系统里编写一个模型。

在模型中,一个字段代表数据表的一列,而form表单中的一个字段代表<form>中的一个<input>元素。

一、创建表单模型

在项目根目录的login文件夹下,新建一个forms.py文件,也就是/login/forms.py,又是我们熟悉的Django组织文件的套路,一个app一套班子!

/login/forms.py中写入下面的代码,是不是有一种编写数据model模型的既视感?

from django import forms

class UserForm(forms.Form):
username = forms.CharField(label="用户名", max_length=128)
password = forms.CharField(label="密码", max_length=256, widget=forms.PasswordInput)

说明:

  • 要先导入forms模块
  • 所有的表单类都要继承forms.Form类
  • 每个表单字段都有自己的字段类型比如CharField,它们分别对应一种HTML语言中<form>内的一个input元素。这一点和Django模型系统的设计非常相似。
  • label参数用于设置<label>标签
  • max_length限制字段输入的最大长度。它同时起到两个作用,一是在浏览器页面限制用户输入不可超过字符数,二是在后端服务器验证用户输入的长度也不可超过。
  • widget=forms.PasswordInput用于指定该字段在form表单里表现为<input type='password' />,也就是密码输入框。

二、修改视图

使用了Django的表单后,就要在视图中进行相应的修改:

from django.shortcuts import render
from django.shortcuts import redirect
from . import models
from django import forms
from login import forms def index(request):
pass
return render(request, 'login/index.html') def login(request):
if request.method == "POST":
login_form = forms.UserForm(request.POST)
message = "请检查填写的内容!"
if login_form.is_valid():
username = login_form.cleaned_data['username']
password = login_form.cleaned_data['password']
try:
user = models.User.objects.get(name=username)
if user.password == password:
return redirect('/index/')
else:
message = "密码不正确!"
except:
message = "用户不存在!"
return render(request, 'login/login.html', locals()) login_form = forms.UserForm()
return render(request, 'login/login.html', locals()) def register(request):
pass
return render(request, 'login/register.html') def logout(request):
pass
return redirect("/index/")

说明:

  • 对于非POST方法发送数据时,比如GET方法请求页面,返回空的表单,让用户可以填入数据;
  • 对于POST方法,接收表单数据,并验证;
  • 使用表单类自带的is_valid()方法一步完成数据验证工作;
  • 验证成功后可以从表单对象的cleaned_data数据字典中获取表单的具体值;
  • 如果验证不通过,则返回一个包含先前数据的表单给前端页面,方便用户修改。也就是说,它会帮你保留先前填写的数据内容,而不是返回一个空表!

另外,这里使用了一个小技巧,Python内置了一个locals()函数,它返回当前所有的本地变量字典,我们可以偷懒的将这作为render函数的数据字典参数值,就不用费劲去构造一个形如{'message':message, 'login_form':login_form}的字典了。这样做的好处当然是大大方便了我们,但是同时也可能往模板传入了一些多余的变量数据,造成数据冗余降低效率。

三、 修改login页面

Django的表单很重要的一个功能就是自动生成HTML的form表单内容。现在,我们需要修改一下原来的login.html文件:

{% extends 'login/base.html' %}
{% load staticfiles %}
{% block title %}登录{% endblock %}
{% block css %}<link href="{% static 'css/login.css' %}" rel="stylesheet"/>{% endblock %} {% block content %}
<div class="container">
<div class="col-md-4 col-md-offset-4">
<form class='form-login' action="/login/" method="post"> {% if message %}
<div class="alert alert-warning">{{ message }}</div>
{% endif %}
{% csrf_token %}
<h2 class="text-center">欢迎登录</h2> {{ login_form }} <button type="reset" class="btn btn-default pull-left">重置</button>
<button type="submit" class="btn btn-primary pull-right">提交</button> </form>
</div>
</div> <!-- /container -->
{% endblock %}

说明:

  • 你没有看错!一个{{ login_form }}就直接完成了表单内容的生成工作!login_form这个名称来自你在视图函数中生成的form实例的变量名!
  • 但是,它不会生成<form>...</form>标签,这个要自己写;
  • 使用POST的方法时,必须添加{% csrf_token %}标签,用于处理csrf安全机制;
  • Django自动为每个input元素设置了一个id名称,对应label的for参数
  • 重置和提交按钮需要自己写,Django不会帮你生成!

我们到浏览器中,看下实际生成的html源码是什么:

<form class='form-login' action="/login/" method="post">

    <div class="alert alert-warning">密码不正确!</div>
<input type='hidden' name='csrfmiddlewaretoken' value='t7MdqJzR7fbiDth5ZQSBpHb22F8sUkjTy32MlEuhXdW8EZPTwcTNuF0PPOHlxKPz' />
<h2 class="text-center">欢迎登录</h2> <tr><th><label for="id_username">用户名:</label></th><td><input type="text" name="username" value="jack" maxlength="128" required id="id_username" /></td></tr>
<tr><th><label for="id_password">密码:</label></th><td><input type="password" name="password" maxlength="256" required id="id_password" /></td></tr> <button type="reset" class="btn btn-default pull-left">重置</button>
<button type="submit" class="btn btn-primary pull-right">提交</button> </form>

也就是说,Django的form表单功能,帮你自动生成了下面部分的代码:

<tr><th><label for="id_username">用户名:</label></th><td><input type="text" name="username" value="jack" maxlength="128" required id="id_username" /></td></tr>
<tr><th><label for="id_password">密码:</label></th><td><input type="password" name="password" maxlength="256" required id="id_password" /></td></tr>

这看起来好像一个<table>标签啊?没错,就是<table>标签,而且是不带<table></table>的,捂脸!

实际上除了通过{{ login_form }}简单地将表单渲染到HTML页面中了,还有下面几种方式:

  • {{ login_form.as_table }} 将表单渲染成一个表格元素,每个输入框作为一个<tr>标签
  • {{ login_form.as_p }} 将表单的每个输入框包裹在一个<p>标签内
  • {{ login_form.as_ul }} 将表单渲染成一个列表元素,每个输入框作为一个<li>标签

注意:上面的渲染方法中都要自己手动编写<table>或者<ul>标签。

重新启动服务器,刷新页面,如下图所示:

四、手动渲染表单字段

直接{{ login_form }}虽然好,啥都不用操心,但是界面真的很丑,往往并不是你想要的,如果你要使用CSS和JS,比如你要引入Bootstarps框架,这些都需要对表单内的input元素进行额外控制,那怎么办呢?手动渲染字段就可以了。

可以通过{{ login_form.name_of_field }}获取每一个字段,然后分别渲染,如下例所示:

<div class="form-group">
{{ login_form.username.label_tag }}
{{ login_form.username}}
</div>
<div class="form-group">
{{ login_form.password.label_tag }}
{{ login_form.password }}
</div>

其中的label标签可以用label_tag方法来生成。这样子更加灵活了,但是灵活的代价就是我们要写更多的代码,又偏向原生的HTML代码多了一点。

但是问题又...又...又来了!刷新登录页面,却是下图的样子:

好像Bootstrap没有生效呀!仔细查看最终生成的页面源码,你会发现,input元素里少了一个CSS的类form-control。这可咋办?

在form类里添加attr属性即可,如下所示修改login/forms.py

from django import forms

class UserForm(forms.Form):
username = forms.CharField(label="用户名", max_length=128, widget=forms.TextInput(attrs={'class': 'form-control'}))
password = forms.CharField(label="密码", max_length=256, widget=forms.PasswordInput(attrs={'class': 'form-control'}))

再次刷新页面,我们熟悉的Bootstarp框架UI又回来了!

实际上,Django针对{{ login_form }}表单,提供了很多灵活的模板语法,可以循环,可以取值,可以针对可见和不可见的部分单独控制,详细内容可以参考教程前面的章节。

Django实战(一)-----用户登录与注册系统4(表单)的更多相关文章

  1. Django实战(一)-----用户登录与注册系统5(图片验证码)

    为了防止机器人频繁登录网站或者破坏分子恶意登录,很多用户登录和注册系统都提供了图形验证码功能. 验证码(CAPTCHA)是一种区分用户是计算机还是人的公共全自动程序. 可以防止恶意破解密码.刷票.论坛 ...

  2. Django实战(一)-----用户登录与注册系统3(前端页面、登录视图)

    基本框架搭建好了后,我们就要开始丰富页面内容了.最起码,得有一个用户登录的表单不是么?(注册的事情我们先放一边.) 一. 原生HTML页面 删除原来的login.html文件中的内容,写入下面的代码: ...

  3. Django实战(一)-----用户登录与注册系统2(数据模型、admin后台、路由视图)

    使用Django开发Web应用的过程中,很多人都是急急忙忙地写视图,写前端页面,把最根本的模型设计给忽略了. 模型中定义了数据如何在数据库内保存,再直白点说就是数据表的定义.这部分工作体现在Djang ...

  4. Django实战(一)-----用户登录与注册系统6(session会话、注册视图)

    因为因特网HTTP协议的特性,每一次来自于用户浏览器的请求(request)都是无状态的.独立的. 通俗地说,就是无法保存用户状态,后台服务器根本就不知道当前请求和以前及以后请求是否来自同一用户.对于 ...

  5. Django实战(一)-----用户登录与注册系统7(邮件确认)

    通常而言,我们在用户注册成功,实际登陆之前,会发送一封电子邮件到对方的注册邮箱中,表示欢迎.进一步的还可能要求用户点击邮件中的链接,进行注册确认. 下面就让我们先看看如何在Django中发送邮件吧. ...

  6. Django实战(一)-----用户登录与注册系统1(环境搭建)

    一.背景 学了一段时间的语法,总感觉入不了门,所以找点小项目练练手,项目来自网络. 二.创建虚拟环境,并安装Django 使用Python中的virtualenv搭建一个mysite_env全新的环境 ...

  7. Django用户登录与注册系统

    一.创建项目 1.1.创建项目和app python manage.py startproject mysite_login python manage.py startapp login 1.2.设 ...

  8. 使用PHP实现用户登录和注册的功能

    登陆界面 login.php <form action="logincheck.php" method="post"> 用户名:<input ...

  9. Java入门:用户登录与注册模块1(实践项目)——分析

    任务描述:用户登录与注册是大多数软件都拥有的一个模块.请编写一个控制台程序,实现用户的登录与注册功能,并且用户能够修改自己信息. [需求分析]由于本程序是一个演示程序,用户的信息我们做简化处理,仅包括 ...

随机推荐

  1. diff和patch

    diff -u:the unified format会将不同的地方放在一起,紧凑易读 . diff original.txt updated.txt c表示在original文件中的m,n行的内容将要 ...

  2. Pyhton对象解释

    python的docstring提供了对每一个类.函数.方法的解释,在他们的定义下面可以有一行Python的标准字符串,该行字符串需要和下面的代码一样的缩进. docstring可以用单引号(')或者 ...

  3. 利用salt搭建hadoop集群

    自动化工具有很多..今天总结一下salt安装hadoop 步骤,学习过程. 1,机器列表 hosts文件    只需要将namenode的两台机器上配置 ,不解释了. 2.salt-master在10 ...

  4. vue基础篇---路由的实现《2》

    现在我们来实现这样一个功能: 一个页面,包含登录和注册,点击不同按钮,实现登录和注册页切换: 编写父组件 index.html <div id="app"> <s ...

  5. tomcat如何访问非webapp下的资源文件

    只要在%tomcathome%\conf\server.xml文件,在标签中加入文件中加入如下代码即可: <Host name="localhost" appBase=&qu ...

  6. shiro的基本认识及做一个简单的授权登陆的例子

    先推荐一个网站,无意中发现的.感觉蛮好的. 推荐一套完整的Shiro Demo,免费的.Shiro Demo:http://www.sojson.com/shiroDemo已经部署到线上,地址是htt ...

  7. C#设计模式(7)——适配器模式

    1.适配器模式介绍 适配器模式的作用是将一个类的接口,转换成客户端希望的另外一种接口,适配器作为原始接口(我们的类中本来具有的功能)和目标接口(客户端希望的功能)之间的桥梁.举个例子:我们知道安卓数据 ...

  8. Uncaught DOMException: Failed to construct 'WebSocket': The URL '/qibao/websocket/service1000' is invalid.

    出现这个问题是构造 WebSocket失败了. js代码改成 //实现化WebSocket对象,指定要连接的服务器地址与端口 建立连接//等同于socket = new WebSocket(path+ ...

  9. CSS-Naming-Conventions--BEM

    BEM BEM : Block Element Modifier There are only two hard problems in Computer Sciences:cache invalid ...

  10. python中\r的意义及用法

    \r的意义 \r 表示将光标的位置回退到本行的开头位置 \b表示将光标的位置回退一位 在python里print会默认进行换行,可以通过修改参数让其不换行 (1) python2中可以在print语句 ...