网站后端.Flask.实战-社交博客开发-资料编辑?
2016-06-29 18:41
561 查看
1.用户资料编辑分两种情况,普通用户只能编辑自己的资料页面,编辑后显示在自己的资料页面,管理员可以编辑任意用户的资料,包括用户所属的角色,如让指定用户称为内容管理员
说明:EditProfileForm为定义的资料编辑表单,由于这个表单中的所有的字段都是可选的,因此长度验证函数允许长度为0
FlaskWeb/app/main/views.py
说明:当form.validate_on_submit()验证失败时,获取当前用户的属性通过form.<field-named>.data完成赋值,当提交表单时,更新查出来的用户对象信息然后在把对象加到数据库中提交.
FlaskWeb/app/templates/base.html
说明:为了让用户能轻易找到编辑页面,可以在base.html基模版中添加一个编辑页面链接
FlaskWeb/app/main/forms.py
说明:WTForms对HTML表单控件<select>进行SelectField包装,从而实现下拉菜单,用来在这个表单中选择用户角色,SelectField实例必须在其choices属性中设置各项,选项必须由一个元组组成的列表,各元组都包含两个元素,选项的标识符和显示在控件中的文本字符串,choices列表在表单的构造函数中设定,其中从Role模型中获取,使用一个查询按照角色名的字母顺序排序所有的角色,元组中的标识符是角色的id,因为这个值为整数,所在在SelectField构造函数中添加coerce=int,从而把字段的值转换为整数而不使用默认的字符串
FlaskWeb/app/main/views.py
说明:此视图函数中,用户由主键id指定,于是使用flask-sqlchemy中的get_or_404()函数,如果提供的id不正确,则返回404错误,用于选择用户的SelectField,在设定这个字段初始值时,role_id被赋值给了field.role.data,这么做的原因在于choices属性中设置的元组列表使用数字标识符标识各项,表单提交后,id从字段data属性中提取,并且查询时会使用提取出来的id值加载角色对象
FlaskWeb/app/templates/base.html
说明:对于不同的角色用户个人设置页面可能不同,如上通过判断是否是管理员来访问不同的用户信息自定义页面
用户级别
FlaskWeb/app/auth/forms.py#!/usr/bin/env python # -*- coding: utf-8 -*- """ # # Authors: limanman # OsChina: http://my.oschina.net/pydevops/ # Purpose: # """ from ..models import User from flask_wtf import Form from wtforms import ValidationError from wtforms.validators import Length, DataRequired, Email, Regexp, EqualTo from wtforms import StringField, PasswordField, BooleanField, SubmitField, TextAreaField class EditProfileForm(Form): realname = StringField(u'真实姓名', validators=[ Length(0, 64, u'长度必须在0-64之间') ]) location = StringField(u'地址信息', validators=[ Length(0, 128, u'长度必须在0-128之间') ]) about_me = TextAreaField(u'个人简介') submit = SubmitField(u'更新')
说明:EditProfileForm为定义的资料编辑表单,由于这个表单中的所有的字段都是可选的,因此长度验证函数允许长度为0
FlaskWeb/app/main/views.py
#!/usr/bin/env python # -*- coding: utf-8 -*- """ # # Authors: limanman # OsChina: http://my.oschina.net/pydevops/ # Purpose: # """ from .. import db from . import main from .forms import EditProfileForm from ..models import Permission, User from flask_login import login_required, current_user from ..decorators import admin_required, permission_required from flask import render_template, redirect, url_for, abort, flash @main.route('/admin') @login_required # @permission_required(Permission.ADMINISTER_POWER) @admin_required def admin(): return redirect(url_for('admin.index')) @main.route('/user/<username>') def user(username): user = User.query.filter_by(username=username).first() if not user: abort(404) return render_template('user.html', user=user) @main.route('/edit-profile/<username>', methods=['GET', 'POST']) @login_required def edit_profile(username): user = User.query.filter_by(username=username).first() if not user: abort(404) form = EditProfileForm() if form.validate_on_submit(): if form.realname.data.strip(): user.realname = form.realname.data if form.location.data.strip(): user.location = form.location.data if form.about_me.data.strip(): user.about_me = form.about_me.data db.session.add(user) db.session.commit() flash(u'信息已更新完毕', 'success') return redirect(url_for('main.user', username=user.username)) form.realname.data = current_user.realname form.location.data = current_user.location form.about_me.data = current_user.about_me return render_template('edit_profile.html', form=form) @main.route('/', methods=['GET', 'POST']) def index(): return render_template('index.html')
说明:当form.validate_on_submit()验证失败时,获取当前用户的属性通过form.<field-named>.data完成赋值,当提交表单时,更新查出来的用户对象信息然后在把对象加到数据库中提交.
FlaskWeb/app/templates/base.html
{%- extends 'bootstrap/base.html' -%} {%- import 'bootstrap/wtf.html' as wtf -%} {%- import 'bootstrap/utils.html' as utils -%} {%- import 'bootstrap/fixes.html' as fixes -%} {%- block html_attribs -%} {{ super() }} lang="zh-cn" {%- endblock -%} {%- block meta -%} {{ super() }} charset="utf-8" {%- endblock -%} {%- block title -%} {{ title|default('Flasky', true) }} {%- endblock -%} {%- block head -%} {{ super() }} {{ fixes.ie8() }} <link rel="shortcut icon" type="image/x-icon" href="{{ url_for('static', filename='favicon.ico') }}"> <link rel="icon" type="image/x-icon" href="{{ url_for('static', filename='favicon.ico') }}"> {%- endblock -%} {%- block navbar -%} <div class="navbar navbar-inverse" role="navigation"> <div class="container"> <div class="navbar-header"> {# 说明: 先不支持响应式 #} <a class="navbar-brand" href="/">Flasky</a> </div> <div> <ul class="nav navbar-nav navbar-left"> <li class="active"><a href="/">Home</a></li> </ul> <ul class="nav navbar-nav navbar-right"> {%- if current_user.is_authenticated -%} <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown">{{ current_user.username }}<b class="caret"></b> </a> <ul class="dropdown-menu"> <li><a href="{{ url_for('main.user', username=current_user.username) }}">个人信息</a></li> <li><a href="{{ url_for('main.edit_profile', username=current_user.username) }}">个人设置</a></li> <li><a href="{{ url_for('auth.logout') }}">退出登出</a></li> </ul> </li> {%- else -%} <li><a href="{{ url_for('auth.login') }}">登录</a></li> <li><a href="{{ url_for('auth.register') }}">注册</a></li> {%- endif -%} </ul> </div> </div> </div> {%- endblock -%} {%- block content -%} <div class="container"> {%- block page_content -%}{%- endblock -%} </div> {%- endblock -%} {%- block styles -%} {{ super() }} {%- endblock -%} {%- block scripts -%} <script type="text/javascript" src="{{ url_for('main.static',filename='js/fixes/respond.min.js') }}"></script> <script type="text/javascript" src="{{ url_for('main.static',filename='js/fixes/html5shiv.min.js') }}"></script> {{ super() }} {{ moment.include_moment(local_js=url_for('main.static', filename='js/moment-with-locales.min.js')) }} {%- endblock -%}
说明:为了让用户能轻易找到编辑页面,可以在base.html基模版中添加一个编辑页面链接
管理级别
1.管理员资料编辑表单比普通表单更加复杂,除了上面的字段外还要能编辑用户的电子邮件,用户名,确认状态和角色FlaskWeb/app/main/forms.py
#!/usr/bin/env python # -*- coding: utf-8 -*- """ # # Authors: limanman # OsChina: http://my.oschina.net/pydevops/ # Purpose: # """ from flask_wtf import Form from ..models import User, Role from wtforms import ValidationError from wtforms.validators import Length, DataRequired, Email, Regexp, EqualTo from wtforms import StringField, PasswordField, BooleanField, SubmitField, TextAreaField, SelectField class EditProfileForm(Form): realname = StringField(u'真实姓名', validators=[ Length(0, 64, u'长度必须在0-64之间') ]) location = StringField(u'地址信息', validators=[ Length(0, 128, u'长度必须在0-128之间') ]) about_me = TextAreaField(u'个人简介') submit = SubmitField(u'更新') class EditProfileAdminForm(Form): email = StringField(u'邮箱地址', validators=[ DataRequired(u'请填写此字段'), Length(1, 64, u'长度必须在1-64之'), Email(u'邮箱地址格式有误'), ]) username = StringField(u'用户名', validators=[ DataRequired(u'请填写此字段'), Length(6, 64, u'长度必须在6-64之间'), Regexp(r'^[a-zA-Z][a-zA-Z0-9_]*$', 0, u'用户名只能包含字母数字下划线,字母开头') ]) is_confirmed = BooleanField(u'邮箱已确认?', default=False) role = SelectField(u'角色设置', coerce=int) realname = StringField(u'真实姓名', validators=[ Length(0, 64, u'长度必须在0-64之间') ]) location = StringField(u'地址信息', validators=[ Length(0, 128, u'长度必须在0-128之间') ]) about_me = TextAreaField(u'个人简介') submit = SubmitField(u'更新') def __init__(self, *args, **kwargs): super(EditProfileAdminForm, self).__init__(*args, **kwargs) role_list = [] for cur_role in Role.query.order_by(Role.name).all(): role_list.append((cur_role.id, cur_role.name)) self.role.choices = role_list def validate_email(self, field): user = User.query.filter_by(email=field.data).first() if user: raise ValidationError(u'邮箱地址已被注册') def validate_username(self, field): user = User.query.filter_by(username=field.data).first() if user: raise ValidationError(u'用户名已被注册')
说明:WTForms对HTML表单控件<select>进行SelectField包装,从而实现下拉菜单,用来在这个表单中选择用户角色,SelectField实例必须在其choices属性中设置各项,选项必须由一个元组组成的列表,各元组都包含两个元素,选项的标识符和显示在控件中的文本字符串,choices列表在表单的构造函数中设定,其中从Role模型中获取,使用一个查询按照角色名的字母顺序排序所有的角色,元组中的标识符是角色的id,因为这个值为整数,所在在SelectField构造函数中添加coerce=int,从而把字段的值转换为整数而不使用默认的字符串
FlaskWeb/app/main/views.py
#!/usr/bin/env python # -*- coding: utf-8 -*- """ # # Authors: limanman # OsChina: http://my.oschina.net/pydevops/ # Purpose: # """ from .. import db from . import main from ..models import Permission, User, Role from flask_login import login_required, current_user from .forms import EditProfileForm, EditProfileAdminForm from ..decorators import admin_required, permission_required from flask import render_template, redirect, url_for, abort, flash @main.route('/admin') @login_required # @permission_required(Permission.ADMINISTER_POWER) @admin_required def admin(): return redirect(url_for('admin.index')) @main.route('/user/<username>') def user(username): user = User.query.filter_by(username=username).first() if not user: abort(404) return render_template('user.html', user=user) @main.route('/edit-profile/<int:id>', methods=['GET', 'POST']) @login_required @admin_required def edit_profile_admin(id): user = User.query.get_or_404(id) form = EditProfileAdminForm() if form.validate_on_submit(): user.email = form.email.data user.username = form.username user.is_confirmed = form.is_confirmed user.role = Role.query.get(form.role.data) user.realname = form.realname.data user.location = form.location.data user.about_me = form.about_me.data db.session.add(user) flash(u'用户信息已更新') return redirect(url_for('main.user', username=user.username)) form.email.data = user.email form.username.data = user.username form.is_confirmed.data = user.is_confirmed form.role.data = user.role_id form.realname.data = user.realname form.location.data = user.location form.about_me.data = user.about_me return render_template('edit_profile.html', form=form, user=user) @main.route('/edit-profile/<username>', methods=['GET', 'POST']) @login_required def edit_profile(username): user = User.query.filter_by(username=username).first() if not user: abort(404) form = EditProfileForm() if form.validate_on_submit(): if form.realname.data.strip(): user.realname = form.realname.data if form.location.data.strip(): user.location = form.location.data if form.about_me.data.strip(): user.about_me = form.about_me.data db.session.add(user) db.session.commit() flash(u'信息已更新完毕', 'success') return redirect(url_for('main.user', username=user.username)) form.realname.data = current_user.realname form.location.data = current_user.location form.about_me.data = current_user.about_me return render_template('edit_profile.html', form=form) @main.route('/', methods=['GET', 'POST']) def index(): return render_template('index.html')
说明:此视图函数中,用户由主键id指定,于是使用flask-sqlchemy中的get_or_404()函数,如果提供的id不正确,则返回404错误,用于选择用户的SelectField,在设定这个字段初始值时,role_id被赋值给了field.role.data,这么做的原因在于choices属性中设置的元组列表使用数字标识符标识各项,表单提交后,id从字段data属性中提取,并且查询时会使用提取出来的id值加载角色对象
FlaskWeb/app/templates/base.html
{%- extends 'bootstrap/base.html' -%} {%- import 'bootstrap/wtf.html' as wtf -%} {%- import 'bootstrap/utils.html' as utils -%} {%- import 'bootstrap/fixes.html' as fixes -%} {%- block html_attribs -%} {{ super() }} lang="zh-cn" {%- endblock -%} {%- block meta -%} {{ super() }} charset="utf-8" {%- endblock -%} {%- block title -%} {{ title|default('Flasky', true) }} {%- endblock -%} {%- block head -%} {{ super() }} {{ fixes.ie8() }} <link rel="shortcut icon" type="image/x-icon" href="{{ url_for('static', filename='favicon.ico') }}"> <link rel="icon" type="image/x-icon" href="{{ url_for('static', filename='favicon.ico') }}"> {%- endblock -%} {%- block navbar -%} <div class="navbar navbar-inverse" role="navigation"> <div class="container"> <div class="navbar-header"> {# 说明: 先不支持响应式 #} <a class="navbar-brand" href="/">Flasky</a> </div> <div> <ul class="nav navbar-nav navbar-left"> <li class="active"><a href="/">Home</a></li> </ul> <ul class="nav navbar-nav navbar-right"> {%- if current_user.is_authenticated -%} <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown">{{ current_user.username }}<b class="caret"></b> </a> <ul class="dropdown-menu"> <li><a href="{{ url_for('main.user', username=current_user.username) }}">个人信息</a></li> {%- if current_user.is_administrator() -%} <li><a href="{{ url_for('main.edit_profile_admin', id=current_user.id) }}">个人设置</a></li> {%- else -%} <li><a href="{{ url_for('main.edit_profile', username=current_user.username) }}">个人设置</a></li> {%- endif -%} <li><a href="{{ url_for('auth.logout') }}">退出登出</a></li> </ul> </li> {%- else -%} <li><a href="{{ url_for('auth.login') }}">登录</a></li> <li><a href="{{ url_for('auth.register') }}">注册</a></li> {%- endif -%} </ul> </div> </div> </div> {%- endblock -%} {%- block content -%} <div class="container"> {%- block page_content -%}{%- endblock -%} </div> {%- endblock -%} {%- block styles -%} {{ super() }} {%- endblock -%} {%- block scripts -%} <script type="text/javascript" src="{{ url_for('main.static',filename='js/fixes/respond.min.js') }}"></script> <script type="text/javascript" src="{{ url_for('main.static',filename='js/fixes/html5shiv.min.js') }}"></script> {{ super() }} {{ moment.include_moment(local_js=url_for('main.static', filename='js/moment-with-locales.min.js')) }} {%- endblock -%}
说明:对于不同的角色用户个人设置页面可能不同,如上通过判断是否是管理员来访问不同的用户信息自定义页面
相关文章推荐
- 如何使用 Flask 编写 Python Web API
- 信息安全聚合 Sec-News 的重构之路
- 在python的WEB框架Flask中使用多个配置文件的解决方法
- python使用Flask框架获取用户IP地址的方法
- Python的Flask框架中Flask-Admin库的简单入门指引
- Python Web框架Flask中使用百度云存储BCS实例
- Python的Flask开发框架简单上手笔记
- Python的Flask站点中集成xhEditor文本编辑器的教程
- 在CentOS上配置Nginx+Gunicorn+Python+Flask环境的教程
- 在Python的Flask框架中验证注册用户的Email的方法
- Python的Flask框架中SERVER_NAME域名项的配置教程
- Flask框架中密码的加盐哈希加密和验证功能的用法详解
- 在Python的Flask框架下收发电子邮件的教程
- Python的Flask框架应用程序实现使用QQ账号登录的方法
- 从源码解析Python的Flask框架中request对象的用法
- 详解Python的Flask框架中生成SECRET_KEY密钥的方法
- Python的Flask框架的简介和安装方法
- 在Python的Flask框架中构建Web表单的教程
- python中Flask框架简单入门实例