24、使用Django Form表单
1、Django Form的作用
Django用Form类描述html表单,帮助或简化操作
- 1、接收和处理用户提交的数据
- 可检查提交的数据
- 可将数据转换成Python的数据类型
- 2、可自动生成html代码
打开具体博客页面,有登录框,那如果我们在其他地方需要登录才能继续操作,那我们就得再写一个form标签,每个需要登录的地方都这样做的话,就比较麻烦、分散。这里我们可以把登录专门放到一个页面,不管哪个地方需要登录,我我们点击那个按钮或者链接,它就跳转到登录页面,登录完成之后再跳转回来,当然这里也可以做成那种弹窗式小窗口,在小窗口登录,这些都是可以实现的。这里我们用第一种方式 跳转页面
在templates下新建登录页面login.html,写入如下代码:
<!-- C:\Users\12482\Desktop\py_learn\Django2.0_chapter46\mysite_env\mysite\templates\login.html -->
{% extends 'base.html' %}
{% load staticfiles %}
{% block title %}
我的网站 | 登录
{% endblock %}
{% block nav_home_active %}active{% endblock %}
{% block content %}
<form action="{% url 'login' %}" method="POST">
{% csrf_token %}
<span>用户名:</span>
<input type="text" name="username"><!--text文本框类型,password密码框,submit按钮类型-->
<span>密码:</span>
<input type="password" name="password">
<input type="submit" value="登录">
</form>
{% endblock %}
接着我们要让blog_detail.html页面可以访问这个登录页面链接,我们打开全局url设置mysite/urls.py,这里有一条处理登录的方法 views.login,那我们修改这个方法,mysite/views.py如下:
修改blog_detail.html如下:
刷新页面:
接着我们要开始实现用Django Form去做东西
2、Django Form的使用
- 创建forms.py文件
- 字段 --> html input 标签
- 每个字段类型都有一个适当的默认Widget类
from django import forms
class NameForm(forms.Form):
your_name = forms.CharField(label='Your name', max_length=100)
这个forms文件需要放到某个app里,而这里我们没有创建登录相关的app,公共操作我们都是放在mysite这个文件夹下面,那么我们就可以在mysite这个文件夹下面新建forms文件写入如下代码:
# # C:\Users\12482\Desktop\py_learn\Django2.0_chapter46\mysite_env\mysite\mysite\forms.py
from django import forms
class LoginForm(forms.Form):
username = forms.CharField()
password = forms.CharField()
接着我们打开登录页面的处理方法mysite/views.py:
再看前端页面login.html
刷新页面,点击“登录”
接着我们要做一些其他更改。比如上面页面里面的“username”“password”我们想要改成中文的
定制forms类,修改forms.py如下:
点击“登录”之后,哪个地方接收这个提交的数据,怎么样去操作?我们再多写一个链接多写一个处理方法的话,就有点繁琐。
这里form表单提交的方式跟普通加载页面不同,它是POST请求方式,而页面加载是GET请求方式,这两个不相同,那么我们可以让它提交到原来渲染页面的处理方法,判断是哪种类型,如果是POST这种类型的话,就说明是提交数据,如果是GET类型,就是加载页面
这里我们回到views.py处理方法,添加一个判断如下:
- 如果请求方式是POST的话,则是提交数据;如果是其他行为,则是加载页面:
- 提交数据部分。需要验证提交的数据是否有效:先接收数据,实例化。判断数据是否有效:
- 如果有效,说明验证通过。如果验证通过,则登录。而登录需要用户名和密码,这两者可以通过login_form去获取,里面有个
cleaned_data
,字典形式,包含了我们所需要的字段信息。 - 获取到用户名和密码这两个信息之后,就可以进行登录操作:
- 判断user是否为None:
- 不为None,说明验证通过,通过的话我们就登录
- (1)登录成功之后有个重定向操作,重定向一个登录成功的页面。跳转方法我们引入redirect
- 登录之后,这里我们就不能用之前referer了。我们要返回到进入登录页面之前的那个页面。这里数据最好要从页面传过来,有两种方式:1、get方式。url链接里写个 “?+参数” 形式。2、post方式。在login.html里面再多加一个字段,写明刚刚那个链接是什么。
- 这里我们采用get方式,修改blog_detail.html如下。然后在views.py里面获取这个from参数就可以(若没有获取到,则默认跳转到首页)
- (2)登录失败,重定向到一个错误页面。但这里页面跳来跳去不太好,我们可以利用form本身的错误集
- 不为None,说明验证通过,通过的话我们就登录
- 判断user是否为None:
- 如果有效,说明验证通过。如果验证通过,则登录。而登录需要用户名和密码,这两者可以通过login_form去获取,里面有个
- 提交数据部分。需要验证提交的数据是否有效:先接收数据,实例化。判断数据是否有效:
在页面点击“登录”后可以看到url里面多了链接信息,是点击跳转之前的页面url信息:
修改mysite\views.py如下:
刷新页面,点击“登录”,随便输入一个错误的用户名和密码登录
如果输入正确的用户名和密码,登录成功后,则跳转到原登录前的页面:
再回到views,继续写 验证不通过 的部分:
from .forms import LoginForm
def login(request):
# 1)如果请求方式是POST的话,则是提交数据行为
if request.method == 'POST':
# 2)提交数据部分。需要验证提交的数据是否有效
# 3)先接收数据,实例化
login_form = LoginForm(request.POST) # 将提交的数据 初始化一下
# 4)判断数据是否有效
if login_form.is_valid(): # 如果有效,说明验证通过
# 5)如果验证通过,则登录。而登录需要用户名和密码,这两者可以通过login_form去获取,里面有个cleaned_data,字典形式,包含了我们所需要的字段信息
username = login_form.cleaned_data['username']
password = login_form.cleaned_data['password']
# 6)获取到用户名和密码这两个信息之后,就可以进行登录操作
user = auth.authenticate(request, username=username, password=password)
if user is not None: # 不为None,说明验证通过,通过的话我们就登录,登录之后有个重定向操作,重定向一个登录成功的页面。跳转方法我们引入redirect
auth.login(request, user)
return redirect(request.GET.get('from', reverse('home'))) # 登录之后,这里我们就不能用之前referer了。我们要返回到进入登录页面之前的那个页面。
# 这里数据最好要从页面传过来,有两种方式:1、get方式。url链接里写个 ?+参数 形式。2、post方式。在login.html里面再多加一个字段,写刚刚那个链接是什么
# 这里我们采用get方式,修改blog_detail.html,然后在views.py里面获取这个from参数就可以(若没有获取到,则默认跳转到首页)
# 登录失败,重定向到一个错误页面。但这里页面跳来跳去不太好,我们可以利用form本身的错误集
else:
login_form.add_error(None, '用户名或密码不正确') # 这里有两个参数:对应的字段名、错误信息
# 之后,我们把form返回回去,它携带了上面加的错误信息“用户名或密码不正确”,就可以把它自动的显示到前端模板页面
context = {}
context['login_form'] = login_form
return render(request, 'login.html', context)
# 如果无效,说明验证未通过。实例化login_form信息也会传给前端页面显示出来
else:
context = {}
context['login_form'] = login_form
return render(request, 'login.html', context)
# 其他行为,则是加载页面
else:
# 实例化
login_form = LoginForm()
# 创建前端页面
context = {}
context['login_form'] = login_form
return render(request, 'login.html', context)
代码整合优化:
def login(request):
# 1)如果请求方式是POST的话,则是提交数据行为
if request.method == 'POST':
# 2)提交数据部分。需要验证提交的数据是否有效
# 3)先接收数据,实例化
login_form = LoginForm(request.POST) # 将提交的数据 初始化一下
# 4)判断数据是否有效
if login_form.is_valid(): # 如果有效,说明验证通过
# 5)如果验证通过,则登录。而登录需要用户名和密码,这两者可以通过login_form去获取,里面有个cleaned_data,字典形式,包含了我们所需要的字段信息
username = login_form.cleaned_data['username']
password = login_form.cleaned_data['password']
# 6)获取到用户名和密码这两个信息之后,就可以进行登录操作
user = auth.authenticate(request, username=username, password=password)
if user is not None: # 不为None,说明验证通过,通过的话我们就登录,登录之后有个重定向操作,重定向一个登录成功的页面。跳转方法我们引入redirect
auth.login(request, user)
return redirect(request.GET.get('from', reverse('home'))) # 登录之后,这里我们就不能用之前referer了。我们要返回到进入登录页面之前的那个页面。
# 这里数据最好要从页面传过来,有两种方式:1、get方式。url链接里写个 ?+参数 形式。2、post方式。在login.html里面再多加一个字段,写刚刚那个链接是什么
# 这里我们采用get方式,修改blog_detail.html,然后在views.py里面获取这个from参数就可以(若没有获取到,则默认跳转到首页)
# 登录失败,重定向到一个错误页面。但这里页面跳来跳去不太好,我们可以利用form本身的错误集
else:
login_form.add_error(None, '用户名或密码不正确') # 这里有两个参数:对应的字段名、错误信息
# 其他行为,则是加载页面
else:
# 实例化
login_form = LoginForm()
# 创建前端页面
context = {}
context['login_form'] = login_form
return render(request, 'login.html', context)
forms.py还有更多的功能,除了定义字段之外,还可以进行一些验证,比如用户名或者密码是否正确,也可以放到这里进行验证。
验证操作放到forms里,登录操作放在views.py的login里
修改forms.py如下:
修改views.py如下:
我们回到login.html模板页面,可以看到渲染出来的页面比较丑比较简陋,我们进行一些优化处理,可以查看Bootstrap文档,搜索“form-control”查看 输入框组。
先修改forms.py如下,这里我们可以在shell下查看下:
修改login.html如下:
这里我们到这里就行,也可以加一个面版,查看Bootstrap文档里面的“带标题的面版”
修改login.html如下:
完善forms.py如下:
我们如果想要去掉“用户名”“密码”后面的冒号,我们需要将login.html修改如下:
另外,将登录的错误信息显示出来,修改login.html如下:
刷新页面,随便输入用户名和密码:
至此,登录部分的代码写完了。
另外我们要写的是注册:
同样的,可以在forms.py加注册的内容:
接下来我们要添加链接、处理方法、对应的模板页面
修改mysite/views.py如下:
修改mysite/urls.py如下:
在templates下新建register.html(复制login.html,稍做修改即可):
<!-- C:\Users\12482\Desktop\py_learn\Django2.0_chapter46\mysite_env\mysite\templates\register.html -->
{% extends 'base.html' %}
{% load staticfiles %}
{% block title %}
我的网站 | 注册
{% endblock %}
{% block nav_home_active %}active{% endblock %}
{% block content %}
<!-- <form action="{% url 'login' %}" method="POST"> 这里的action链接如果是指向自己的话,可以不写或者只写一个#号-->
<div class="container">
<div class="row">
<div class="col-xs-4 col-xs-offset-4">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">注册</h3>
</div>
<div class="panel-body">
<form action="" method="POST">
{% csrf_token %}
{% for field in reg_form %}
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{{ field }}
<p class="text-danger">{{ field.errors.as_text }}</p>
{% endfor %}
<span class="pull-left text-danger">{{ login_form.non_field_errors }}</span>
<input type="submit" value="注册" class="btn btn-primary pull-right">
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
接着回头来完善views.py里面的register处理方法:
接着在博客详情模板页面加上一个注册的选项
修改blog_detail.html如下:
刷新页面
点击“注册”
以下测试注册功能:
(1)用户名只输入一位:
(2)用户名输入已经存在的用户
(3)邮箱只输入一位:
(4)密码只输入一位:
(5)两次密码输入不一致
(6)成功注册后,页面跳转至