Python的Flask框架中實現(xiàn)登錄用戶的個人資料和頭像的教程
用戶資料頁面
在用戶資料頁面,基本上沒有什么特別要強調(diào)和介紹的新概念。只需要創(chuàng)建一個含有HTML的新視圖函數(shù)模板頁面即可。
下面是視圖函數(shù)(項目目錄/views.py):
@app.route('/user/<nickname>')
@login_required
def user(nickname):
user = User.query.filter_by(nickname = nickname).first()
if user == None:
flash('不存在用戶:' + nickname + '!')
return redirect(url_for('index'))
posts = [
{ 'author': user, 'body': 'Test post #1' },
{ 'author': user, 'body': 'Test post #2' }
]
return render_template('user.html',
user = user,
posts = posts)
這里的@app.route標(biāo)識主要是用來說明此視圖函數(shù)不同于之前的那些。我們定義了一個名為<nickname>的參數(shù)。在函數(shù)里面它會轉(zhuǎn)化成跟它同名的參數(shù),當(dāng)用戶有請求的時候,例如這樣的一個URL:URL/user/miguel,次視圖函數(shù)就會識別為有一個名為nickname值為'miguel'的參數(shù),即nickname = 'miguel'。
沒必要為此方法的實現(xiàn)過程感到驚訝。首先我們需要通過把轉(zhuǎn)化后的nickname參數(shù)作為條件,嘗試著從數(shù)據(jù)庫里把此用戶的數(shù)據(jù)調(diào)用出來。如果沒有查詢到數(shù)據(jù),我們就像之前那樣,給用戶一個錯誤的提示并且跳轉(zhuǎn)到主頁去。
一旦我們找到了改用戶,我們就在模板下面來顯示該用戶的文章。要注意下的是在用戶資料頁面我們只讓顯示該用戶的文章,所以文章的作者要是該用戶。
初始化的視圖模板非常的簡單(項目目錄/templates/user.html):
<!-- extend base layout -->
{% extends "base.html" %}
{% block content %}
<h1>用戶昵稱: {{user.nickname}}!</h1>
<hr>
{% for post in posts %}
<p>
{{post.author.nickname}} 發(fā)布了: <b>{{post.body}}</b>
</p>
{% endfor %}
{% endblock %}
用戶資料頁面就做好了,不過在站點中還沒有指向改頁面的鏈接地址。為了讓用戶很方便的來查看自己的資料信息我們就把鏈接地址放到最上面的導(dǎo)航上去(項目目錄/templates/base.html):
<div>Microblog:
<a href="{{ url_for('index') }}">Home</a>
{% if g.user.is_authenticated() %}
| <a href="{{ url_for('user', nickname = g.user.nickname) }}">你的個人資料</a>
| <a href="{{ url_for('logout') }}">退出登陸</a>
{% endif %}
</div>
注意一下我們已經(jīng)給函數(shù)傳參了之后的和之前的URL。
現(xiàn)在就來試一試這個項目。點擊上面的“你的資料”鏈接就會跳轉(zhuǎn)到用戶資料頁面。由于我們還沒有指向一個隨意用戶資料頁面的鏈接地址,所以在這里如果你想看他人的資料,就需要自己手動輸入一下地址了。比如你想看miguel的資料,那么地址就是:http://localhost:5000/user/miguelt
頭像部分
我相信你會覺得目前的用戶資料頁面看起來很單調(diào)。為了好看,我們就來添加用戶頭像的功能。
為了避免我們服務(wù)器需要來處理大量上傳后的頭像圖片,我們在這里就使用Gravatar給咋們提供的用戶頭像即可。
鑒于返回一個用戶頭像是屬于用戶這塊的,所以我們就把代碼放在theUserclass里面(項目目錄/models.py):
from hashlib import md5
# ...
class User(db.Model):
# ...
def avatar(self, size):
return 'http://www.gravatar.com/avatar/' + md5(self.email).hexdigest() +
'?d=mm&s=' + str(size)
avatar將會返回用戶頭像圖片的地址, 根據(jù)你的需要來請求你想要的圖片尺寸像素。
從Gravatar上得到圖像圖片很簡單。你只需要用md5把用戶的郵箱hash加密之后合并成上面的那種url形式即可。當(dāng)然你也可以自由選擇自 定義圖像大小。其中“d=mm”是設(shè)置用戶在沒有Gravatar賬號的情況下顯示的默認(rèn)頭像?!癿m”選項會返回一張只有人輪廓的灰色圖片,稱之為“謎 樣人”。而“s=”選項是用來設(shè)置返回你給定的圖片尺寸像素。
當(dāng)然Gravatar也有自己的文檔來描述URL的拼接技術(shù)!
到這里Userclass就可以返回一個用戶頭像的圖片了,我們就需要把這個整合到用戶資料布局去(項目目錄/templates/user.html):
<!-- extend base layout -->
{% extends "base.html" %}
{% block content %}
<table>
<tr valign="top">
<td><img src="{{user.avatar(128)}}"></td>
<td><h1>用戶昵稱: {{user.nickname}}</h1></td>
</tr>
</table>
<hr>
{% for post in posts %}
<p>
{{post.author.nickname}} 發(fā)布了: <b>{{post.body}}</b>
</p>
{% endfor %}
{% endblock %}
我們設(shè)計Userclass來返回用戶頭像的亮點在于:如果某一天我們要是覺得Gravatar網(wǎng)站上的頭像不是我們所想要的頭像的時候,我們只需要我們只需要重寫一下頭像處理的函數(shù)來返回我們想要的地址即可(即使有人盜鏈指向我們的服務(wù)器,我們也可以保護好自己的主機),這樣一來只需要修改這么點點,所以的模板都還是自動正常運行。
我們已經(jīng)把用戶頭像部分添加到了用戶資料詳情頁面的頂部去了,不過在頁面底部我們還有顯示文章的沒做,在文章前面我們也需要顯示一下用戶的頭像。當(dāng) 然在用戶資料頁面需要對所以的文章都顯示同樣的頭像,不過要是把頭像函數(shù)移動到主頁去來給所以的文章都顯示作者的頭像,那該多好。
我們只需要稍稍修改模板文件即可實現(xiàn)給文章顯示相應(yīng)作者頭像的功能(項目目錄/templates/user.html):
<!-- extend base layout -->
{% extends "base.html" %}
{% block content %}
<table>
<tr valign="top">
<td><img src="{{user.avatar(128)}}"></td>
<td><h1>用戶昵稱: {{user.nickname}}</h1></td>
</tr>
</table>
<hr>
{% for post in posts %}
<table>
<tr valign="top">
<td><img src="{{post.author.avatar(50)}}"></td><td><i>{{post.author.nickname}}
發(fā)布了:</i><br>{{post.body}}</td>
</tr>
</table>
{% endfor %}
{% endblock %}
這就是到此為止我們的用戶資料頁面:
微博客用戶詳情頁面

重復(fù)使用子模板
用戶資料頁面顯示了用戶自己的文章,不過網(wǎng)站的首頁需要顯示此刻不同用戶文章。在這里就有兩個用于顯示 用戶文章的模板文件了。我們可以直接復(fù)制把處理顯示文章的那段代碼然后直接粘貼到新的模板,其實那并不是最理想的方法,倘若有一天我們需要修改下顯示文章 那塊,我們就需要來更新所以的那些含有文章顯示代碼的模板文件。
反之,我們將會去新建一個子模板文件來處理文章顯示的功能,之后在需要顯示文章的時候包含一下這個文件即可。
開始我們還是來創(chuàng)建一個子空模板文件,然后把用戶資料頁面中展示文章的那段代碼復(fù)制過來(項目目錄/templates/post.html):
<table>
<tr valign="top">
<td><img src="{{post.author.avatar(50)}}"></td><td><i>{{post.author.nickname}}
發(fā)布了:</i><br>{{post.body}}</td>
</tr>
</table>
然后我們使用Jinja2的包含功能調(diào)用一下該子模板文件(項目目錄/templates/user.html)
<!-- extend base layout -->
{% extends "base.html" %}
{% block content %}
<table>
<tr valign="top">
<td><img src="{{user.avatar(128)}}"></td>
<td><h1>用戶昵稱: {{user.nickname}}</h1></td>
</tr>
</table>
<hr>
{% for post in posts %}
{% include 'post.html' %}
{% endfor %}
{% endblock %}
一旦有了完整的頁面我們就可以按照上面的方法去調(diào)用下子模板來顯示文章,不過現(xiàn)在還不急說,將在后面章節(jié)的教程中說到。
更多相關(guān)個人信息
盡管到此用戶信息頁面比較精密了,不過還是有許多信息沒有顯示出來。用戶大多喜歡在網(wǎng)站上顯示自己更多的信息,因此我們就可以讓用戶填寫自己的信息顯示在這里。當(dāng)然我們也可以記錄下用戶每次登陸到本站的的時間,顯示到他們自己的資料詳情頁。
為了顯示等多的信息我們就需要更新下數(shù)據(jù)庫。特別需要在Userclass里面新加字段(項目目錄/models.py):
class User(db.Model):
id = db.Column(db.Integer, primary_key = True)
nickname = db.Column(db.String(64), unique = True)
email = db.Column(db.String(120), index = True, unique = True)
role = db.Column(db.SmallInteger, default = ROLE_USER)
posts = db.relationship('Post', backref = 'author', lazy = 'dynamic')
about_me = db.Column(db.String(140))
last_seen = db.Column(db.DateTime)
我們每次修改數(shù)據(jù)庫的時候就需要生成新的記錄(migration)。需要注意下我們在處理數(shù)據(jù)更新到數(shù)據(jù)庫的時候記得創(chuàng)建一個(migration),現(xiàn)在我們就來看下最后結(jié)果。我們只需要下面的代碼就可以把新加的兩個字段更新到數(shù)據(jù)庫里去了:
./db_migrate.py
當(dāng)然相應(yīng)的響應(yīng)腳本是
New migration saved as db_repository/versions/003_migration.py Current database version: 3
現(xiàn)在我們新加的兩個字段就保存到數(shù)據(jù)庫了。不過需要提醒的是在window系統(tǒng)下面調(diào)用此腳本是有點不一樣的。
如果不支持?jǐn)?shù)據(jù)遷移的話你還得手動修改數(shù)據(jù)庫,否則你就需要刪除之后重新從頭開始創(chuàng)建數(shù)據(jù)。
接下來我們就需要修改下用戶詳情頁來顯示我們剛添加的字段(項目目錄/templates/user.html):
<!-- extend base layout -->
{% extends "base.html" %}
{% block content %}
<table>
<tr valign="top">
<td><img src="{{user.avatar(128)}}"></td>
<td>
<h1>用戶昵稱: {{user.nickname}}</h1>
{% if user.about_me %}<p>{{user.about_me}}</p>{% endif %}
{% if user.last_seen %}<p><i>Last seen on: {{user.last_seen}}</i></p>{% endif %}
</td>
</tr>
</table>
<hr>
{% for post in posts %}
{% include 'post.html' %}
{% endfor %}
{% endblock %}
由于我們需要只有當(dāng)用戶自己填寫了這兩個字段的時候才顯示出來,所以我們主要利用Jinja2的判斷條件來顯示這些字段即可。
對于這點,對所有的用戶而言,這兩個字段都是空的,什么都不會顯示的。
最后顯示的字段(last_seen)就特別的好處理。需要注意的是在上面我們已經(jīng)設(shè)置了用于注冊用戶請求的(flask.g和global, asg.user)接收參數(shù)。也就是需要在這個最佳段來記錄用戶的登陸時間(項目目錄/views.py):
from datetime import datetime
# ...
@app.before_request
def before_request():
g.user = current_user
if g.user.is_authenticated():
g.user.last_seen = datetime.utcnow()
db.session.add(g.user)
db.session.commit()
如果你登陸了之后就會在資料詳情頁面顯示最后的登陸時間,當(dāng)然如果你每刷新一次頁面的話相應(yīng)的登陸時間就會自動更新。這是由于當(dāng)瀏覽器沒刷新一次就會去請求我們上面設(shè)置的接收參數(shù)并更新數(shù)據(jù)庫的處理函數(shù)。
在這里我們記錄的是國際標(biāo)準(zhǔn)時間UTC時區(qū)。在之前的章節(jié)中我們也提到了怎么去儲存一個適合所有時區(qū)的時間戳,這就會在有一個負(fù)面的錯誤信息,因為在所有用戶的資料頁面顯示的都是UTC的時區(qū)的時間,這個問題我會在接下來說關(guān)于出來時間和日期的章節(jié)中詳細講解。
想顯示關(guān)于用戶的更多信息,我們得給他們一個鏈接, 最適合放在用戶資料的編輯頁面。
編輯用戶詳細資料
創(chuàng)建一個用戶資料編輯頁面那真是太簡單了,我們只需要創(chuàng)建下面的web表單即可(項目目錄/forms.py):
from flask.ext.wtf import Form, TextField, BooleanField, TextAreaField
from flask.ext.wtf import Required, Length
class EditForm(Form):
nickname = TextField('nickname', validators = [Required()])
about_me = TextAreaField('about_me', validators = [Length(min = 0, max = 140)])
視圖模板文件(項目目錄/templates/edit.html):
<!-- extend base layout -->
{% extends "base.html" %}
{% block content %}
<h1>Edit Your Profile</h1>
<form action="" method="post" name="edit">
{{form.hidden_tag()}}
<table>
<tr>
<td>你的昵稱:</td>
<td>{{form.nickname(size = 24)}}</td>
</tr>
<tr>
<td>關(guān)于自己:</td>
<td>{{form.about_me(cols = 32, rows = 4)}}</td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="保存"></td>
</tr>
</table>
</form>
{% endblock %}
最后當(dāng)然就是創(chuàng)建視圖的方法(項目目錄/views.py):
from forms import LoginForm, EditForm
@app.route('/edit', methods = ['GET', 'POST'])
@login_required
def edit():
form = EditForm()
if form.validate_on_submit():
g.user.nickname = form.nickname.data
g.user.about_me = form.about_me.data
db.session.add(g.user)
db.session.commit()
flash('Your changes have been saved.')
return redirect(url_for('edit'))
else:
form.nickname.data = g.user.nickname
form.about_me.data = g.user.about_me
return render_template('edit.html',
form = form)
方便用戶編輯,我們需要在用戶的個人資料頁面添加一個到此頁面的鏈接地址(項目目錄/templates/user.html):
<!-- extend base layout -->
{% extends "base.html" %}
{% block content %}
<table>
<tr valign="top">
<td><img src="{{user.avatar(128)}}"></td>
<td>
<h1>用戶昵稱: {{user.nickname}}</h1>
{% if user.about_me %}<p>{{user.about_me}}</p>{% endif %}
{% if user.last_seen %}<p><i>最后登陸時間: {{user.last_seen}}</i></p>{% endif %}
{% if user.id == g.user.id %}<p><a href="{{url_for('edit')}}">修改資料</a></p>{% endif %}
</td>
</tr>
</table>
<hr>
{% for post in posts %}
{% include 'post.html' %}
{% endfor %}
{% endblock %}
不過你需要判斷的一下,條件就是只有當(dāng)用戶瀏覽自己的個人資料頁面的時候才顯示該鏈接,而不是瀏覽任何人的個人資料頁面都顯示出來。
下面是最新個人資料頁面的截圖,包含了我們新加的所以字段,也含有“關(guān)于我”的文字:

最后一點留給你自己去研究了
貌似通過上面的一些列制作,個人資料頁面感覺已經(jīng)很完善了,對不?仔細想來,是這樣不過我們還有一些bug需要修復(fù)下。
不知道你有沒有發(fā)現(xiàn)?
提醒下你吧,在之前的章節(jié)中我們?yōu)g覽用戶登陸的時候其實我就已經(jīng)提到過這個bug的?,F(xiàn)在我們在上面的代碼片中也犯了同樣錯。
仔細想想吧,如果你知道是什么問題的話可以在下面評論中說下。我將會在下一個章節(jié)詳細地說此bug,并說怎么去修正它。
跟以前一樣我會把今天說講到的代碼打包提供下載
下載地址 microblog-0.6.zip.
相關(guān)文章
django第一個項目127.0.0.1:8000不能訪問的解決方案詳析
django項目服務(wù)啟動后無法通過127.0.0.1訪問,下面這篇文章主要給大家介紹了關(guān)于django第一個項目127.0.0.1:8000不能訪問的解決方案,需要的朋友可以參考下2022-10-10
Python多叉樹的構(gòu)造及取出節(jié)點數(shù)據(jù)(treelib)的方法
今天小編就為大家分享一篇Python多叉樹的構(gòu)造及取出節(jié)點數(shù)據(jù)(treelib)的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-08-08
python 處理telnet返回的More,以及get想要的那個參數(shù)方法
今天小編就為大家分享一篇python 處理telnet返回的More,以及get想要的那個參數(shù)方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-02-02
django rest framework之請求與響應(yīng)(詳解)
下面小編就為大家?guī)硪黄猟jango rest framework之請求與響應(yīng)(詳解)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧,希望對大家有所幫助2017-11-11
在Windows系統(tǒng)上搭建Nginx+Python+MySQL環(huán)境的教程
這篇文章主要介紹了在Windows系統(tǒng)上搭建Nginx+Python+MySQL環(huán)境的教程,文中使用flup中間件及FastCGI方式連接,需要的朋友可以參考下2015-12-12
通過Python實現(xiàn)自動填寫調(diào)查問卷
這篇文章主要介紹了通過Python實現(xiàn)自動填寫調(diào)查問卷的相關(guān)資料,需要的朋友可以參考下2017-09-09
總結(jié)分析python數(shù)據(jù)化運營關(guān)聯(lián)規(guī)則
本文內(nèi)容主要介紹了python數(shù)據(jù)化運營中關(guān)聯(lián)規(guī)則的一般應(yīng)用場景,以及關(guān)聯(lián)規(guī)則的實現(xiàn),并例舉了適應(yīng)的應(yīng)用示例,方便大家更直觀的理解應(yīng)用2021-08-08
對django的User模型和四種擴展/重寫方法小結(jié)
今天小編就為大家分享一篇對django的User模型和四種擴展/重寫方法小結(jié),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-08-08

