关于本站
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天) 用户认证:前言博文的末尾。
效果如下:
这次就添加了通用的表单模版和修改昵称、密码的功能。下一个功能我考虑加上第三方登录和忘记密码的处理。