标签:
1. 数据库中添加用户信息
app/models.py: 添加用户资料列
class User(UserMixin, db.Model):
#...
name = db.Column(db.String(64))
location = db.Column(db.String(64))
about_me = db.Column(db.Text())
member_since = db.Column(db.DateTime(), default=datatime.utcnow)
last_seen = db.Column(db.DateTime(), default=datatime.utcnow)
datetime.utcnow 后面没有 (),因为 db.Column()的 default 参数可以接受函数作为默认值,所以每次需要生成默认值时,db.Column() 都会调用指定的函数。
member_since字段创建时的初始值是当前时间,只需使用默认值即可,
last_seen 字段创建时的初始值也是当前时间,但用户每次访问网站后,这个值都会被刷新。可以在User模型中添加一个方法完成这个操作。
app/models.py: 刷新用户的最后访问时间
class User(UserMixin, db.Model):
#...
def ping(self):
self.last_seen = datatime.utcnow()
db.session.add(self)
每次收到用户的请求时都要调用该ping()方法。由于 auth 蓝本中的 before_app_request 处理程序会在每次请求前运行,所以能很轻松地实现这个需求。
app/auth/views.py: 更新已登录用户的访问时间
@auth.before_app_request
def before_request():
if current_user.is_authenticated():
current_user.ping()
#...
2. 用户信息页面
app/main/views.py: 信息页面的路由
@main.route(‘/user/<username>‘)
def user(username):
user = User.query.filter_by(username=username).first()
if user is None:
abort(404)
return render_template(‘user.html‘, user=user)
app/templates/user.html:用户信息页面的模板
{% block page_content %}
<div class="page-header">
<h1>{{ user.username }}</h1>
{% if user.name or user.location %}
<p>
{% if user.name %}{{ user.name }}{% endif %}
{% if user.location %}
From <a href="http://maps.google.com/?q={{ user.location }}">
{{ user.location }}
</a>
{% endif %}
</p>
{% endif %}
{% if current_user.is_administrator() %}
<p><a href="mailto:{{ user.email }}">{{ user.email }}</a></p>
{% endif %}
{% if user.about_me %}<p>{{ user.about_me }}</p>{% endif %}
<p>
Member since {{ moment(user.member_since).format(‘L‘) }}.
Last seen {{ moment(user.last_seen).fromNow() }}.
</p>
</div>
{% endblock %}
location 字段被渲染成指向谷歌地图的查询链接。
如果登录用户是管理员,那么就显示用户的电子邮件地址,且渲染成 mailto 链接。
在导航条中添加一个连接到用户资料界面的链接
app/templates/base.html
{% if current_user.is_authenticated() %}
<li>
<a href="{{ url_for(‘main.user‘, username=current_user.username) }}">
Profile
</a>
</li>
{% endif %}
通过判断is_authenticated(), 未登录用户看不到那个按钮
3. 编辑页面
3.1 普通用户的编辑页面
app/main/forms.py: 编辑表单
class EditProfileForm(Form):
name = StringField(‘Name‘, validators=[Length(0, 64)])
location = StringField(‘Location‘, validators=[Length(0, 64)])
about_me = TextAreaField(‘About Me‘)
submit = SubmitField(‘Submit‘)
app/main/views.py: 资料编辑路由
@main.route(‘/edit-profile‘, methods=[‘GET‘, ‘POST‘])
@login_required
def edit_profile():
form = EditProfileForm()
if form.validate_on_submit():
current_user.name = form.name.data
current_user.location = form.location.data
current_user.about_me = form.about_me.data
db.session.add(current_user)
flash(‘Your profile has been updated.‘)
return redirect(url_for(‘.user‘, username=current_user.username))
form.name.data = current_user.name
form.location.data = current_user.location
form.about_me.data = current_user.about_me
return render_template(‘edit_profile.html‘, form=form)
3.2 管理员的编辑页面
管理员使用的页面编辑表单比普通用户的表单更加复杂。除了前面的 3 个资料信息字段之外,管理员在表单中还要能编辑用户的电子邮件、用户名、确认状态和角色。
app/main/forms.py: 管理员编辑表单
class EditProfileAdminForm(Form):
email = StringField(‘Email‘, validators=[Required(), Length(1, 64), Email()])
username = StringField(‘Username‘, validators=[
Required(), Length(1, 64), Regexp(‘^[A-Za-z][A-Za-z0-9_.]*$‘, 0,
‘Usernames must have only letters, ‘
‘numbers, dots or underscores‘)])
confirmed = BooleanField(‘Confirmed‘)
role = SelectField(‘Role‘, coerce=int)
name = StringField(‘Real name‘, validators=[Length(0, 64)])
location = StringField(‘Location‘, validators=[Length(0, 64)])
about_me = TextAreaField(‘About me‘)
submit = SubmitField(‘Submit‘)
def __init__(self, user, *args, **kwargs):
super(EditProfileAdminForm, self).__init__(*args, **kwargs)
self.role.choices = [(role.id, role.name) for role in Role.query.order_by(Role.name).all()]
self.user = user
def validate_email(self, field):
if field.data != self.user.email and User.query.filter_by(email=field.data).first():
raise ValidationError(‘Email already registered.‘)
def validate_username(self, field):
if field.data != self.user.username and User.query.filter_by(username=field.data).first():
raise ValidationError(‘Username already in use.‘)
WTForms 对 HTML 表单控件 <select> 进行 SelectField 包装,从而实现下拉列表,用来在这个表单中选择用户角色。
SelectField 实例必须在其 choices 属性中设置各选项。选项必须是一个由元组组成的列表,各元组都包含两个元素:选项的标识符和显示在控件中的文本字符串。
choices 列表在表单的构造函数中设定,其值从 Role 模型中获取,使用一个查询按照角色名的字母顺序排列所有角色。
元组中的标识符是角色的 id,因为这是个整数,所以在 SelectField 构造函数中添加 coerce=int 参数,从而把字段的值转换为整数,而不使用默认的字符串。
app/main/views.py: 管理员编辑页面路由
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(user=user)
if form.validate_on_submit():
user.email = form.email.data
user.username = form.username.data
user.confirmed = form.confirmed.data
user.role = Role.query.get(form.role.data)
user.name = form.name.data
user.location = form.location.data
user.about_me = form.about_me.data
db.session.add(user)
flash(‘The profile has been updated.‘)
return redirect(url_for(‘.user‘, username=user.username))
form.email.data = user.email
form.username.data = user.username
form.confirmed.data = user.confirmed
form.role.data = user.role_id
form.name.data = user.name
form.location.data = user.location
form.about_me.data = user.about_me
return render_template(‘edit_profile.html‘, form=form, user=user)
再探讨一下用于选择用户角色的 SelectField。
设定这个字段的初始值时,role_id 被赋值给了 field.role.data,这么做的原因在于 choices 属性中设置的元组列表使用数字标识符表示各选项。
表单提交后,id 从字段的 data 属性中提取,并且查询时会使用提取出来的 id 值加载角色对象。
表单中声明 SelectField 时使用 coerce=int 参数,其作用是保证这个字段的 data 属性值是整数。
2015-05-24
标签:
原文地址:http://www.cnblogs.com/whuyt/p/4526124.html