使用者資料頁面
在使用者資料頁面,基本上沒有什麼特別要強調和介紹的新概念。只需要建立一個含有HTML的新視圖函數模板頁面即可。
下面是視圖函數(項目目錄/views.py):
@app.route('/user/')@login_requireddef 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標識主要是用來說明此視圖函數不同於之前的那些。我們定義了一個名為的參數。在函數裡面它會轉化成跟它同名的參數,當使用者有請求的時候,例如這樣的一個URL:URL/user/miguel,次視圖函數就會識別為有一個名為nickname值為'miguel'的參數,即nickname = 'miguel'。
沒必要為此方法的實現過程感到驚訝。首先我們需要通過把轉化後的nickname參數作為條件,嘗試著從資料庫裡把此使用者的資料調用出來。如果沒有查詢到資料,我們就像之前那樣,給使用者一個錯誤的提示並且跳轉到首頁去。
一旦我們找到了改使用者,我們就在模板下面來顯示該使用者的文章。要注意下的是在使用者資料頁面我們只讓顯示該使用者的文章,所以文章的作者要是該使用者。
初始化的視圖模板非常的簡單(項目目錄/templates/user.html):
{% extends "base.html" %} {% block content %}使用者暱稱: {{user.nickname}}!
{% for post in posts %} {{post.author.nickname}} 發布了: {{post.body}}
{% endfor %}{% endblock %}
使用者資料頁面就做好了,不過在網站中還沒有指向改頁面的連結地址。為了讓使用者很方便的來查看自己的資料資訊我們就把連結地址放到最上面的導航上去(項目目錄/templates/base.html):
Microblog: Home {% if g.user.is_authenticated() %} | 你的設定檔 | 退出登陸 {% endif %}
注意一下我們已經給函數傳參了之後的和之前的URL。
現在就來試一試這個項目。點擊上面的“你的資料”連結就會跳轉到使用者資料頁面。由於我們還沒有指向一個隨意使用者資料頁面的連結地址,所以在這裡如果你想看他人的資料,就需要自己手動輸入一下地址了。比如你想看miguel的資料,那麼地址就是:http://localhost:5000/user/miguelt
頭像部分
我相信你會覺得目前的使用者資料頁面看起來很單調。為了好看,我們就來添加帳戶圖片的功能。
為了避免我們伺服器需要來處理大量上傳後的頭像圖片,我們在這裡就使用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將會返回帳戶圖片圖片的地址, 根據你的需要來請求你想要的圖片尺寸像素。
從Gravatar上得到映像圖片很簡單。你只需要用md5把使用者的郵箱hash加密之後合并成上面的那種url形式即可。當然你也可以自由選擇自 定義映像大小。其中“d=mm”是設定使用者在沒有Gravatar帳號的情況下顯示的預設頭像。“mm”選項會返回一張只有人輪廓的灰色圖片,稱之為“謎 樣人”。而“s=”選項是用來設定返回你給定的圖片尺寸像素。
當然Gravatar也有自己的文檔來描述URL的拼接技術!
到這裡Userclass就可以返回一個帳戶圖片的圖片了,我們就需要把這個整合到使用者資料布局去(項目目錄/templates/user.html):
{% extends "base.html" %} {% block content %}
{% for post in posts %}
{{post.author.nickname}} 發布了: {{post.body}}
{% endfor %}{% endblock %}
我們設計Userclass來返回帳戶圖片的亮點在於:如果某一天我們要是覺得Gravatar網站上的頭像不是我們所想要的頭像的時候,我們只需要我們只需要重寫一下頭像處理的函數來返回我們想要的地址即可(即使有人盜鏈指向我們的伺服器,我們也可以保護好自己的主機),這樣一來只需要修改這麼點點,所以的模板都還是自動正常運行。
我們已經把帳戶圖片部分添加到了使用者資料詳情頁面的頂部去了,不過在頁面底部我們還有顯示文章的沒做,在文章前面我們也需要顯示一下使用者的頭像。當 然在使用者資料頁面需要對所以的文章都顯示同樣的頭像,不過要是把頭像函數移動到首頁去來給所以的文章都顯示作者的頭像,那該多好。
我們只需要稍稍修改模板檔案即可實現給文章顯示相應作者頭像的功能(項目目錄/templates/user.html):
{% extends "base.html" %} {% block content %}
{% for post in posts %}
|
{{post.author.nickname}} 發布了: {{post.body}} |
{% endfor %}{% endblock %}
這就是到此為止我們的使用者資料頁面:
微部落格使用者詳情頁面
重複使用子模板
使用者資料頁面顯示了使用者自己的文章,不過網站的首頁需要顯示此刻不同使用者文章。在這裡就有兩個用於顯示 使用者文章的模板檔案了。我們可以直接複製把處理顯示文章的那段代碼然後直接粘貼到新的模板,其實那並不是最理想的方法,倘若有一天我們需要修改下顯示文章 那塊,我們就需要來更新所以的那些含有文章顯示代碼的模板檔案。
反之,我們將會去建立一個子模板檔案來處理文章顯示的功能,之後在需要顯示文章的時候包含一下這個檔案即可。
開始我們還是來建立一個子空模板檔案,然後把使用者資料頁面中展示文章的那段代碼複製過來(項目目錄/templates/post.html):
|
{{post.author.nickname}} 發布了: {{post.body}} |
然後我們使用Jinja2的包含功能調用一下該子模板檔案(項目目錄/templates/user.html)
{% extends "base.html" %} {% block content %}
{% for post in posts %} {% include 'post.html' %}{% endfor %}{% endblock %}
一旦有了完整的頁面我們就可以按照上面的方法去調用下子模板來顯示文章,不過現在還不急說,將在後面章節的教程中說到。
更多相關個人資訊
儘管到此使用者資訊頁面比較精密了,不過還是有許多資訊沒有顯示出來。使用者大多喜歡在網站上顯示自己更多的資訊,因此我們就可以讓使用者填寫自己的資訊顯示在這裡。當然我們也可以記錄下使用者每次登陸到本站的的時間,顯示到他們自己的資料詳情頁。
為了顯示等多的資訊我們就需要更新下資料庫。特別需要在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)
我們每次修改資料庫的時候就需要產生新的記錄(migration)。需要注意下我們在處理資料更新到資料庫的時候記得建立一個(migration),現在我們就來看下最後結果。我們只需要下面的代碼就可以把新加的兩個欄位更新到資料庫裡去了:
./db_migrate.py
當然相應的響應指令碼是
New migration saved as db_repository/versions/003_migration.pyCurrent database version: 3
現在我們新加的兩個欄位就儲存到資料庫了。不過需要提醒的是在window系統下面調用此指令碼是有點不一樣的。
如果不支援資料移轉的話你還得手動修改資料庫,否則你就需要刪除之後重新從頭開始建立資料。
接下來我們就需要修改下使用者詳情頁來顯示我們剛添加的欄位(項目目錄/templates/user.html):
{% extends "base.html" %} {% block content %}
|
使用者暱稱: {{user.nickname}} {% if user.about_me %}{{user.about_me}} {% endif %} {% if user.last_seen %}Last seen on: {{user.last_seen}} {% endif %} |
{% for post in posts %} {% include 'post.html' %}{% endfor %}{% endblock %}
由於我們需要只有當使用者自己填寫了這兩個欄位的時候才顯示出來,所以我們主要利用Jinja2的判斷條件來顯示這些欄位即可。
對於這點,對所有的使用者而言,這兩個欄位都是空的,什麼都不會顯示的。
最後顯示的欄位(last_seen)就特別的好處理。需要注意的是在上面我們已經設定了用於註冊使用者請求的(flask.g和global, asg.user)接收參數。也就是需要在這個最佳段來記錄使用者的登陸時間(項目目錄/views.py):
from datetime import datetime# ...@app.before_requestdef 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()
如果你登陸了之後就會在資料詳情頁面顯示最後的登陸時間,當然如果你每重新整理一次頁面的話相應的登陸時間就會自動更新。這是由於當瀏覽器沒重新整理一次就會去請求我們上面設定的接收參數並更新資料庫的處理函數。
在這裡我們記錄的是國際標準時間UTC時區。在之前的章節中我們也提到了怎麼去儲存一個適合所有時區的時間戳記,這就會在有一個負面的錯誤資訊,因為在所有使用者的資料頁面顯示的都是UTC的時區的時間,這個問題我會在接下來說關於出來時間和日期的章節中詳細講解。
想顯示關於使用者的更多資訊,我們得給他們一個連結, 最適合放在使用者資料的編輯頁面。
編輯使用者詳細資料
建立一個使用者資料編輯頁面那真是太簡單了,我們只需要建立下面的web表單即可(項目目錄/forms.py):
from flask.ext.wtf import Form, TextField, BooleanField, TextAreaFieldfrom 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):
{% extends "base.html" %} {% block content %}Edit Your Profile
{% endblock %}
最後當然就是建立視圖的方法(項目目錄/views.py):
from forms import LoginForm, EditForm @app.route('/edit', methods = ['GET', 'POST'])@login_requireddef 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):
{% extends "base.html" %} {% block content %}
|
使用者暱稱: {{user.nickname}} {% if user.about_me %}{{user.about_me}} {% endif %} {% if user.last_seen %}最後登陸時間: {{user.last_seen}} {% endif %} {% if user.id == g.user.id %}修改資料 {% endif %} |
{% for post in posts %} {% include 'post.html' %}{% endfor %}{% endblock %}
不過你需要判斷的一下,條件就是只有當使用者瀏覽自己的設定檔頁面的時候才顯示該連結,而不是瀏覽任何人的設定檔頁面都顯示出來。
下面是最新設定檔頁面的,包含了我們新加的所以欄位,也含有“關於我”的文字:
最後一點留給你自己去研究了
貌似通過上面的一些列製作,設定檔頁面感覺已經很完善了,對不?仔細想來,是這樣不過我們還有一些bug需要修複下。
不知道你有沒有發現?
提醒下你吧,在之前的章節中我們瀏覽使用者登陸的時候其實我就已經提到過這個bug的。現在我們在上面的代碼片中也犯了同樣錯。
仔細想想吧,如果你知道是什麼問題的話可以在下面評論中說下。我將會在下一個章節詳細地說此bug,並說怎麼去修正它。
跟以前一樣我會把今天說講到的代碼打包提供下載
下載地址 microblog-0.6.zip.