本部分内容为Flasky实现用户资料页面,显示用户在网站中的活动情况,并且这个URL要简短易记。
一. 资料信息
app/models.py:用户信息字段
class User(UserMixin, db.Model):
__tablename__ = "users"
...
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=datetime.utcnow)
last_seen = db.Column(db.DateTime, default=datetime.utcnow)
新添加的字段保存用户的真实姓名,所在地,自我介绍,注册日期和最后访问日期。about_me字段类型是db.Text(),db.String()和db.Text()的主要区别在于后者是变长字段,不需要指定最大长度。
两个时间戳的默认值都是当前时间。default参数可以接收函数作为默认值。故datetime.utcnow后没有()。
last_seen字段默认值也是创建时的当前时间,但用户每次访问网站后都要刷新:
app/models.py:刷新用户的最后访问时间
class User(UserMixin, db.Model):
def ping(self):
self.last_seen = datetime.utcnow()
db.session.add(self)
db.session.commit()
因为每次收到用户请求时都要调用ping()方法,我们可以在之前定义的before_app_request中完成。因为auth蓝本中的before_app_request处理程序会在每次请求前运行,所以能很轻松地实现这个需求。
app/auth/views.py:更新已登录用户的最后访问时间
@auth.before_app_request
def before_request():
if current_user.is_authenticated:
current_user.ping()
if not current_user.confirmed and request.endpoint \
and request.blueprint != 'auth' and request.endpoint != 'static':
return redirect(url_for('auth.unconfirmed'))
二. 用户资料界面
app/main/views.py:资料页面的路由
@main.route('/user/<username>')
def user(username):
user = User.query.filter_by(username=username).first_or_404()
return render_template('user.html', user=user)
这个视图函数会先在数据库中搜索URL中指定的用户名,如果找到,则渲染模板user.html,并把用户名作为参数传入模板。如果传入路由的用户名不存在,则返回404错误。
app/templates/user.html:用户资料页面的模板
{% extends "base.html" %}
{% block title %}Flasky - {{ user.username }}{% endblock %}
{% block page_content %}
<div class="page-header">
<img class="img-rounded profile-thumbnail" src="{{ user.gravatar(size=168) }}">
<div class="profile-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>
<p>
{% if user == current_user %}
<a class="btn btn-default" href="{{ url_for('.edit_profile') }}">Edit Profile</a>
{% endif %}
{% if current_user.is_administrator() %}
<a class="btn btn-danger" href="{{ url_for('.edit_profile_admin', id=user.id) }}">Edit Profile [Admin]</a>
{% endif %}
</p>
</div>
</div>
{% endblock %}
- 用户的location字段被渲染成指向谷歌地图的查询链接,点击打开后将显示一个地图,以所标位置为中心;
- 如果登录的用户是管理员,显示各用户的电子邮件地址,且渲染成mailto:链接,便于管理员联系用户;
- 两个时间戳使用Flask-Moment渲染;
- 最后2个链接分别是用户级资料管理器和管理员级资料管理器,将在下一篇博文中介绍;此处需要注意:如果访问user界面时,是当前登录用户的账号,才渲染用户级资料管理器。并且在用户是管理员账号时,还需要额外显示管理员级用户资料编辑器。
app/templates/base.html:在导航栏中添加指向资料页面的链接
<ul class="nav navbar-nav">
<li><a href="{{ url_for('main.index') }}">Home</a></li>
{% if current_user.is_authenticated %}
<li><a href="{{ url_for('main.user', username=current_user.username) }}">Profile</a></li>
{% endif %}
</ul>
测试运行结果(关于用户头像部分,将在后续博文介绍):