您的位置:首页 > 运维架构 > 网站架构

网站后端.Flask.实战-社交博客开发-资料编辑?

2016-06-29 18:41 561 查看
1.用户资料编辑分两种情况,普通用户只能编辑自己的资料页面,编辑后显示在自己的资料页面,管理员可以编辑任意用户的资料,包括用户所属的角色,如让指定用户称为内容管理员

用户级别

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 -%}

说明:对于不同的角色用户个人设置页面可能不同,如上通过判断是否是管理员来访问不同的用户信息自定义页面
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息