关于本站
1、基于Django+Bootstrap开发
2、主要发表本人的技术原创博客
3、本站于 2015-12-01 开始建站
添加用户中心之后,进一步加上修改昵称和密码功能。
鉴于这个功能是需要提交表单,而且还需要验证数据。我准备使用django的表单。当然也可以自己写html页面和处理响应的方法。那个登录和注册我就是这么处理的。
Django的表单实际上和模型比较相似,都是定义字段给views.py里面的方法处理。而且表单可以通过模型生成。
在user_ex文件夹(我自己创建用于集中存放用户相关的脚本)下面创建forms.py文件。创建用于修改昵称的表单模型:
#coding:utf-8
from django import forms
from django.core.exceptions import ValidationError
from django.contrib.auth.models import User
class ChangeNickForm(forms.Form):
"""change the nick name form"""
#旧昵称,hidden类型,用于判断是否有修改
old_nickname = forms.CharField(widget=forms.HiddenInput(attrs={'id':'old_nickname'}))
#新昵称
nickname = forms.CharField(label=u'新的昵称', max_length=20,
widget=forms.TextInput(attrs={'class':'form-control', 'id':'nickname', 'placeholder':u"请输入您的昵称"}),
error_messages={'required':u'昵称不能为空'})
#nickname验证方法
def clean_nickname(self):
old_nickname = self.cleaned_data.get('old_nickname')
nickname = self.cleaned_data.get('nickname')
is_exist = User.objects.filter(first_name=nickname).count()>0
if is_exist:
#用事先写入hidden的昵称判断是否是自己的昵称
if old_nickname == nickname:
raise ValidationError(u'您当前的昵称就是“%s”,写一个新的吧' % nickname)
else:
raise ValidationError(u'“%s”已被使用,请重新输入' % nickname)
else:
return nickname这里继承forms.Form类,里面的属性则是表单的字段。CharField是字段类型,这个和模型里面的字段类型差不多。
字段默认是必填的,可以在字段实例化中加入required=False设置为非必填。
error_messages则是自定义为空的时候提示文本。
其中最为复杂的是widget设置,该属性可以自定义在html的渲染。TextInput则渲染成<input type="text"/>。在attrs中可以设置class、id等属性。
另外,使用Django表单最好用的是验证方法。我这里是采用我最喜欢用的方法 clean_ + 字段名。表单验证还有其他方法:参考其他人的博文。
表单模型创建好之后,打开views.py写处理方法:
#coding:utf-8
from django.shortcuts import render_to_response, render
from .forms import ChangeNickForm
#装饰器,登录判断
def check_login(func):
def wrapper(request):
#登录判断,若没登录则跳转到前面写的信息提示页面
if not request.user.is_authenticated():
data = {}
data['goto_url'] = '/'
data['goto_time'] = 3000
data['goto_page'] = True
data['message'] = u'您尚未登录,请先登录'
return render_to_response('message.html',data)
else:
return func(request)
return wrapper
@check_login
def nickname_change(request):
data = {}
data['form_title'] = u'修改昵称'
data['submit_name'] = u' 确定 '
if request.method == 'POST':
#表单提交
form = ChangeNickForm(request.POST)
#验证是否合法
if form.is_valid():
#修改数据库
nickname = form.cleaned_data['nickname']
request.user.first_name = nickname
request.user.save()
#页面提示
data['goto_url'] = reverse('user_info')
data['goto_time'] = 3000
data['goto_page'] = True
data['message'] = u'修改昵称成功,修改为“%s”' % nickname
return render_to_response('message.html',data)
else:
#正常加载
nickname = request.user.first_name or request.user.username
#用initial给表单填写初始值
form = ChangeNickForm(initial={
'old_nickname': nickname,
'nickname': nickname,
})
data['form'] = form
return render(request, 'form.html', data)这里用了装饰器验证是否登录了,若没登录则跳转到信息提示页面,若登录了,就继续执行这个方法。之前一直不太理解这个逻辑,自己写了一遍就立马通了,哈哈。
Django的表单处理方法需要判断method请求类型,若为POST,则是表单提交了;若是GET,则是正常加载。
这个代码比较简单,我就不详细说明。最后,这个表单渲染使用一个通用的表单模版。
{% extends "base.html" %}
{% block title %}杨仕航的博客{% endblock %}
{% block content %}
{#通用表单页面#}
<div class="row">
<div class="col-md-6 col-md-offset-3" >
<div id="panel_form" class="panel panel-default">
<div class="panel-body">
<h3 class="form_title">{{form_title}}</h3>
<form method='post'>
{%csrf_token%}
{% for field in form %}
{# 区分是否是hidden字段 #}
{% if field.is_hidden %}
{{ field }}
{% else %}
<div class="input-group">
<label class="input-group-addon" for="{{ field.id_for_label }}">
{{ field.label }}
</label>
{{ field }}
</div>
{# 错误提示信息 #}
<p class="text-danger text-right">
{{ field.errors.as_text }}
</p>
{%endif%}
{%endfor%}
<div class="text-right">
<input class="btn btn-primary" id="btn_submit"
type="submit" value="{{submit_name}}"/>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
{% block extra_footer %}
<style type="text/css">
.form_title{
margin-bottom: 1em;
padding-bottom: 0.5em;
border-bottom: 1px #ccc solid;
}
form div{
margin-top:1em;
}
#btn_submit{
margin-top: 1em;
}
#panel_form{
margin-top: 2em;
margin-bottom: 3em;
}
</style>
{% endblock %}这个表单模版写得比较通用。可以显示字段,标题,错误信息等等。稍微说明一下:
form: 表单对象,可以遍历里面的字段
field: 遍历的字段,自动渲染成input标签
field.is_hidden: 判断字段是否是hidden类型
field.label: 字段的标签名
field.errors.as_text: 字段的错误文本信息
form_title: 表单标题
submit_name: 提交按钮的名称
只要传递表单标题,提交按钮标题和表单对象即可使用这个通用表单模版。效果是这样的:

提交有错误信息的效果:

多个字段,标题可以用全角的空格控制字符数到达一致宽度:

在加上url设置和对应的模版,这样就完成了修改昵称的功能
url(r'^nickname_change$','user_ex.views.nickname_change',name='nickname_change'),
写了不少框架性的东西之后,再加上修改密码的功能就比较方便了。
这里有一个验证旧密码是否正确的问题,需要和用户名对应起来。
验证方法在forms.py文件中,无法取到request对象。这里还是采用把重要信息写到表单的hidden字段中的方法。先把用户名写到表单中,验证的时候再拿出来判断。所以需要表单字段有4个:用户名(hidden隐藏)、旧密码、新密码、重复输入的密码。
在刚刚的forms.py再添加一个表单模型:
#coding:utf-8
from django import forms
from django.core.exceptions import ValidationError
#再import下面两个
from django.contrib.auth.models import User #用户模型
from django.contrib.auth import authenticate #验证密码是否正确
class ChangePwdForm(forms.Form):
"""change the password form"""
username = forms.CharField(widget=forms.HiddenInput())
pwd_old = forms.CharField(label=u'旧的密码', max_length=36,
widget=forms.PasswordInput(
attrs={'class':'form-control', 'id':'pwd_old','placeholder':u'请输入旧密码,验真身'}))
pwd_1 = forms.CharField(label=u'新的密码', max_length=36,
widget=forms.PasswordInput(
attrs={'class':'form-control', 'id':'pwd_1','placeholder':u'请输入6-36位的密码'}))
pwd_2 = forms.CharField(label=u'再输一遍', max_length=36,
widget=forms.PasswordInput(
attrs={'class':'form-control', 'id':'pwd_2','placeholder':u'重复新的密码确保正确'}))
#验证两个新密码是否一致
def clean_pwd_2(self):
pwd_1 = self.cleaned_data.get('pwd_1')
pwd_2 = self.cleaned_data.get('pwd_2')
if pwd_1 != pwd_2:
raise ValidationError(u'两次输入的密码不一致,再输入一次吧')
if len(pwd_2) < 6 or len(pwd_2) > 36:
raise ValidationError(u'密码长度需要在6-36之间')
return pwd_2
#验证旧密码是否正确
def clean_pwd_old(self):
username = self.cleaned_data.get('username')
pwd_old = self.cleaned_data.get('pwd_old')
user = authenticate(username=username, password=pwd_old)
if user is None:
raise ValidationError(u'旧密码不正确,验真身失败')
return pwd_old然后在views.py添加处理方法:
from django.contrib.auth.models import User #用户模型
from django.contrib.auth import authenticate #验证密码是否正确
#导入表单模型
from .forms import ChangeNickForm, ChangePwdForm
@check_login
def password_change(request):
data = {}
data['form_title'] = u'修改密码'
data['submit_name'] = u' 确定 '
if request.method == 'POST':
#表单提交
form = ChangePwdForm(request.POST)
#验证是否合法
if form.is_valid():
#修改数据库
username = request.user.username
pwd = form.cleaned_data['pwd_2']
request.user.set_password(pwd)
request.user.save()
#重新登录
user = authenticate(username=username, password=pwd)
if user is not None:
login(request, user)
#页面提示
data['goto_url'] = reverse('user_info')
data['goto_time'] = 3000
data['goto_page'] = True
data['message'] = u'修改密码成功,请牢记新密码'
return render_to_response('message.html',data)
else:
#正常加载
username = request.user.username
form = ChangePwdForm(initial={'username':username})
data['form'] = form
return render(request, 'form.html', data)再加上url链接和修改对应的html加上链接即可
url(r'^password_change$','user_ex.views.password_change',name='password_change'),
其中message.html模版是显示消息的,可以参考我的网站搭建(第13天) 用户认证:前言博文的末尾。
效果如下:

这次就添加了通用的表单模版和修改昵称、密码的功能。下一个功能我考虑加上第三方登录和忘记密码的处理。