我的网站搭建(第20天) 修改昵称和密码

  • 发布时间:2016年6月2日 09:31
  • 作者:杨仕航
* 该文是基于Python2.7开发的,最新Python3.x和Django2.x视频教程可以前往 >> Django2.0视频教程

添加用户中心之后,进一步加上修改昵称和密码功能。

鉴于这个功能是需要提交表单,而且还需要验证数据。我准备使用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天) 用户认证:前言博文的末尾。

效果如下:


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

上一篇:Django点赞功能实现

下一篇:我的网站搭建(第19天) 用户中心

评论列表

智慧如你,不想发表一下意见吗?

新的评论

清空