第六章 个人信息页和Avatars[一个图片网站]
本章介绍构建一个用户个人信息页,同时可以针对个人信息进行编辑更新。
Tip:在个人信息页的模板中,我自己把img元素换成本地的图片相对路径表达式,图片显示不出来。可能这跟框架有关系,需要把图片换成url引用格式。
一、用户个人信息页
1、构建个人信息页,在路由中设置url,带有user参数:
http:/…?user=username。
@app.route('/user/<username>') #<username>参数:可以传给user视图函数
@login_required
def user(username):
#first_or_404:返回查询的第一个结果,如果未查到,返回404。
user = User.query.filter_by(username=username).first_or_404()
posts = [
{'author': user, 'body': 'Test post #1'},
{'author': user, 'body': 'Test post #2'}
]
return render_template('user.html', user=user, posts=posts)
2、构建个人信息html。
{% extends "base.html" %}
{% block content %}
<h1>User: {{ user.username }}</h1>
<hr>
{% for post in posts %}
<p>
{{ post.author.username }} says: <b>{{ post.body }}</b>
</p>
{% endfor %}
{% endblock %}
3、为了方便用户查看自己信息,在导航栏增加一个菜单“Profile”。
<div>
Microblog:
<a href="{{ url_for('index') }}">Home</a>
{% if current_user.is_anonymous %}
<a href="{{ url_for('login') }}">Login</a>
{% else %}
<a href="{{ url_for('user', username=current_user.username) }}">Profile</a>
<a href="{{ url_for('logout') }}">Logout</a>
{% endif %}
</div>
二、Avatars
Gravatar提供一个图片服务。用户可以通过邮箱来关联一张图片。默认提供的图片的大小是8080px。它提供了一个接口来访问图片: https://www.gravatar.com/avatar/…/s=。s代表图片的大小。
1、在用户信息界面增加图片
app/templates/user.htm
{% extends "base.html" %}
{% block content %}
<table>
<tr valign="top">
<td><img src="{{ user.avatar(128) }}"></td>
<td><h1>User: {{ user.username }}</h1></td>
</tr>
</table>
<hr>
{% for post in posts %}
<p>
{{ post.author.username }} says: <b>{{ post.body }}</b>
</p>
{% endfor %}
{% endblock %}
三、Jinja2子模板
除了在个人信息页用到文章呈现格式,在首页也同样保留这种风格。根据独立性原则,可以为这种公用部分做成一个子模板。
app/templates/_post.html:
<table>
<tr valign="top">
<td><img src="{{ post.author.avatar(36) }}"></td>
<td>{{ post.author.username }} says:<br>{{ post.body }}</td>
</tr>
</table>
在个人信息页把通用部分用子模板代替。
{% include ‘_post.html’ %}:切入子模板。
{% extends "base.html" %}
{% block content %}
<table>
<tr valign="top">
<td><img src="{{ user.avatar(128) }}"></td>
<td><h1>User: {{ user.username }}</h1></td>
</tr>
</table>
<hr>
{% for post in posts %}
{% include '_post.html' %}
{% endfor %}
{% endblock %}
四、更有意思的个人信息
1、增加两个信息:个人签名及上次时间。
app/models.py:
class User(UserMixin, db.Model):
# ...
about_me = db.Column(db.String(140))
last_seen = db.Column(db.DateTime, default=datetime.utcnow)
一旦数据库结构发生变动,我们就需要migrate及upgrade数据库。
4、重新设计个人信息页
{% extends "base.html" %}
{% block content %}
<table>
<tr valign="top">
<td><img src="{{ user.avatar(128) }}"></td>
<td>
<h1>User: {{ user.username }}</h1>
{% if user.about_me %}<p>{{ user.about_me }}</p>{% endif %}
{% if user.last_seen %}<p>Last seen on: {{ user.last_seen }}</p>{% endif %}
</td>
</tr>
</table>
<hr>
{% for post in posts %}
{% include '_post.html' %} #Jinja2's include语法
{% endfor %}
{% endblock %}
五、记录用户上次访问时间
在视图函数中,我们可以把网页发起request时的时间记录到last_seen字段。
但是当网页很多,如果在每个页面视图中都加入这种记录方法,那是不太切实际的。
所以,可以有一种更智慧的替代方法:
app/routes.py:
from datetime import datetime
@app.before_request
def before_request():
if current_user.is_authenticated:
current_user.last_seen = datetime.utcnow()
db.session.commit()
@app.before_request:这个装饰器的作用是可以在发起request前执行我们定义的代码。
六、个人信息编辑页
1、设置编辑页Form结构
app/forms.py:
from wtforms import StringField, TextAreaField, SubmitField
from wtforms.validators import DataRequired, Length
# ...
class EditProfileForm(FlaskForm):
username = StringField('Username', validators=[DataRequired()])
about_me = TextAreaField('About me', validators=[Length(min=0, max=140)])
submit = SubmitField('Submit')
validators=[Length(min=0, max=140)]:定义多行文本框的字数范围。
2、设计编辑页Html:用户可以修改名称,添加或编辑个人描述信息。
app/templates/edit_profile.html:
{% extends "base.html" %}
{% block content %}
<h1>Edit Profile</h1>
<form action="" method="post">
{{ form.hidden_tag() }}
<p>
{{ form.username.label }}<br>
{{ form.username(size=32) }}<br>
{% for error in form.username.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</p>
<p>
{{ form.about_me.label }}<br>
{{ form.about_me(cols=50, rows=4) }}<br>
{% for error in form.about_me.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</p>
<p>{{ form.submit() }}</p>
</form>
{% endblock %}
3 、设置扉页编辑视图函数
app/routes.py
from app.forms import EditProfileForm
@app.route('/edit_profile', methods=['GET', 'POST'])
@login_required
def edit_profile():
form = EditProfileForm()
if form.validate_on_submit():
current_user.username = form.username.data
current_user.about_me = form.about_me.data
db.session.commit() #把新值传入数据库
flash('Your changes have been saved.')
return redirect(url_for('edit_profile'))
elif request.method == 'GET':
form.username.data = current_user.username
form.about_me.data = current_user.about_me
return render_template('edit_profile.html', title='Edit Profile',
form=form)
4 、在用户扉页最底下增加一个“”编辑个人信息页链接”
app/templates/user.html:
{% if user == current_user %}
<p><a href="{{ url_for('edit_profile') }}">Edit your profile</a></p>
{% endif %}