Flask Web 開發 關注者
來源:程序員人生 發布時間:2016-10-10 08:46:17 閱讀次數:2891次
學到這1章,感覺有點回到第8章的味道......有幾個坑還是后期需要靜下心來補的
對模型間的關系,準備另外單獨拎出來寫1篇測試文章,這里留個位置給鏈接吧
#
# 留位置給番外篇
#

上圖是1個自援用的關系圖,就用于像關注和被關注這樣,關聯表兩邊只有1個實體(用戶)的情況的。
本例的關聯表是follows,其中每行都表示1個用戶關注了另外一個用戶。圖中左側表示的1對多關系把用戶和follows 表中的1組記錄聯系起來,用戶是關注者。圖中右側表示
的1對多關系把用戶和follows 表中的1組記錄聯系起來,用戶是被關注者。
上面這句話甚么意思呢?
就是在follows表格里面,他的組成情勢是2個列,follower_id和followed_id,里面的id分別是主動關注的人的id和被關注者的id
class Follow(db.Model):
__tablename__ = 'follows'
follower_id = db.Column(db.Integer, db.ForeignKey('users.id'),primary_key=True)
followed_id = db.Column(db.Integer, db.ForeignKey('users.id'),primary_key=True)
timestamp = db.Column(db.DateTime, default=datetime.utcnow)
從Follow類的屬性定義里面我們就可以看到,follower_id作為外鍵,對應的是users.id, 而followed_id作為外鍵,對應的也是user.id

再來看對應的users表,也就是User類。
需要特別注意的是foreign_keys的值,
followed表示已關注的人,他對應的是Follow類里面的follower_id這個屬性,也就是,關注了哪些人,具體的值是id號
followers表示自己的粉絲,對應的是Follow類里面的followed_id,這個有點拗口,這個實際上是自己粉絲的id
關于lazy,已轉載了其他先輩的1篇文章,而關于cascade,是和刪除對象時候,關聯表格里面的內容會不會1起刪掉有關系的,后續再說
class User(UserMixin,db.Model):
#...
followed = db.relationship('Follow',foreign_keys=[Follow.follower_id],
backref=db.backref('follower', lazy='joined'),
lazy='dynamic',cascade='all, delete-orphan')
followers = db.relationship('Follow',foreign_keys=[Follow.followed_id],
backref=db.backref('followed', lazy='joined'),
lazy='dynamic',cascade='all, delete-orphan')


接著是給User實例添加方法
關注的話,你肯定最少要做1個按鈕給用戶,那這個按鈕設計到2個功能,關注和取消關注,2個狀態,是不是已關注,是不是已被關注
class User(UserMixin,db.Model):
#...
def follow(self, user):
if not self.is_following(user):
f = Follow(follower=self, followed=user)
db.session.add(f)
def unfollow(self, user):
f = self.followed.filter_by(followed_id=user.id).first()
if f:
db.session.delete(f)
def is_following(self, user):
return self.followed.filter_by(followed_id=user.id).first() is not None
def is_followed_by(self, user):
return self.followers.filter_by(follower_id=user.id).first() is not None
follow() 方法手動把Follow 實例插入關聯表,從而把關注者和被關注者聯接起來,并讓程序有機會設定自定義字段的值。聯接在1起的兩個用戶被手動傳入Follow 類的構造器,創建1個Follow 新實例,然后像平常1樣,把這個實例對象添加到
數據庫會話中。注意,這里無需手動設定timestamp 字段,由于定義字段時指定了默許值,即當前日期和時間。unfollow() 方法使用followed 關系找到聯接用戶和被關注用戶的Follow 實例。若要燒毀這兩個用戶之間的聯接,只需刪除這個Follow
對象便可。is_following() 方法和is_followed_by() 方法分別在左右兩邊的1對多關系中搜索指定用戶,如果找到了就返回True。
以上文字是書上的,可以看到,follow()方法最后通過db.session.add來插入新對象f,而unfollow()方法則是通過db.session.delete來刪除這個實例
分步講授下,在follow方法內,他通過self.is_following(user)來檢查,當前用戶針對user是不是已是關注的狀態,下面的is_following方法你可以看到,return出來的是not None
也就是說,follow方法在檢查結果是not (not None)的情況下,會繼續插入新的Follow實例,最后插入數據庫
而unfollow方法則是,通過self對象的followed屬性查找關注了多少人,然后通過followed_id=user.id這句,找出目前這個user對象并賦予給f
如果f存在,則通過session刪除f對象
is_following方法,通過self對象的關注人里面,用user.id來檢查自己是不是已關注這個人,返回結果not None,非空
is_followed_by,1樣,看self對象自己的粉絲群里面,通過user.id找找是不是有這個人,返回結果也是not None,非空
以上2個方法是表示1個狀態,而不是功能性方法。
{% if current_user.can(Permission.FOLLOW) and user != current_user %}
{% if not current_user.is_following(user) %}
<a href="{{url_for('.follow',username=user.username)}}"
class = "btn btn-primary">Follow</a>
{% else %}
<a href="{{url_for('.unfollow',username=user.username)}}"
class = "btn btn-default">Unfollow</a>
{% endif %}
{% endif %}
<a href="{{url_for('.followers',username=user.username)}}">
Followers: <span class="badge">{{ user.followers.count() }}</span>
</a>
<a href="{{ url_for('.followed_by',username=user.username) }}">
Following: <span class="badge">{{ user.followed.count() }}</span>
</a>
{% if current_user.is_authenticated and user != current_user and
user.is_following(current_user)%}
| <span class="label label-default">Follows you</span>
{% endif %}
前端渲染寫好以后,就要寫路由控制了
@main.route('/follow/<username>')
@login_required
@permission_required(Permission.FOLLOW)
def follow(username):
user = User.query.filter_by(username=username).first()
if user is None:
flash('Invalid user.')
return redirect(url_for('.index'))
if current_user.is_following(user):
flash('You are already following this user.')
return redirect(url_for('.user',username=username))
current_user.follow(user)
flash('You are now following %s.' % username)
return redirect(url_for('.user',username=username))
@main.route('/unfollow/<username>')
@login_required
@permission_required(Permission.FOLLOW)
def unfollow(username):
user = User.query.filter_by(username=username).first()
if user is None:
flash('Invalid user.')
return redirect(url_for('.index'))
if not current_user.is_following(user):
flash('You are not following this user.')
return redirect(url_for('.user',username=username))
current_user.unfollow(user)
flash('You are now unfollow %s'%username)
return redirect(url_for('.user',username=username))
follow和unfollow為1組
follow的邏輯是:有2個條件,需要已登錄狀態,需要有FOLLOW權限,通過url里面的username,過濾出該對象用戶,隨落后行判斷
如果用戶不存在,則提示flash消息,無功效戶
如果用戶已關注了該用戶,則提示flash消息,已關注該用戶
如果沒有關注,則履行當前用戶的follow方法,關注該用戶
unfollow的邏輯1樣
@main.route('/followers/<username>')
def followers(username):
user = User.query.filter_by(username=username).first()
if user is None:
flash('Invalid user.')
return redirect(url_for('.index'))
page = request.args.get('page',1,type=int)
pagination = user.followers.paginate(page,per_page=current_app.config['FLASKY_FOLLOWERS_PER_PAGE'],
error_out=False)
follows = [{'user':item.follower,'timestamp':item.timestamp}
for item in pagination.items]
return render_template('followers.html',user=user,title="Followers of",endpoint='.followers',
pagination=pagination,follows=follows)
@main.route('/followed-by/<username>')
def followed_by(username):
user = User.query.filter_by(username=username).first()
if user is None:
flash('Invalid user.')
return redirect(url_for('.index'))
page = request.args.get('page',1,type=int)
pagination = user.followed.paginate(page,per_page=current_app.config['FLASKY_FOLLOWERS_PER_PAGE'],
error_out=False)
follows = [{'user':item.follower,'timestamp':item.timestamp}
for item in pagination.items]
return render_template('followers.html',user=user,title="Followed by",
endpoint='.followed_by',pagination=pagination,
follows=follows)
隨后2個是該用戶的粉絲頁面和所關注的人的頁面
邏輯和上面差不多,也是通過username來過濾出該用戶
如果用戶沒有,則提示flash消息
否則,則進行分頁顯示你的粉絲隊伍和偶像隊伍
先來看看整體效果圖

點了關注以后的變化

粉絲頁面

生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈