1. 程式人生 > >基於python的web應用開發-添加關註者

基於python的web應用開發-添加關註者

templates maps classes else 解決方法 必須 簡化 head html

社交web允許用戶之間相互聯系。

例如:

關註者、好友、聯系人、聯絡人或夥伴。

記錄兩個用戶之間的定向聯系,在數據庫查詢中也要使用這種聯系。

一、論數據庫關系

一對多關系

數據庫使用關系建立記錄之間的聯系。其中,一對多關系是最常用的關系類型,它把一個記錄和一組相關的記錄聯系在一起。實現這種關系,要在“多”這一層加一個外鍵,指向“一”這一側,例如下列代碼:

class Role(db.Model):
    __tablename__ = roles

  id = db.Column(db.Integer,primary_key = True) #... users = db.relationship(
User, backref=role, lazy=dynamic) class User(UserMixin, db.Model): __tablename__ = users #... role_id = db.Column(db.Integer, db.ForeignKey(roles.id))

其中,users的數據庫表中添加了一個外鍵role_id 指向了roles表的id

大部分的其他關系類型都可以從一對多類型中衍生。

多對一關系從“多”這一側看,就是一對多關系。一對一關系類型是簡化版的一對多關

多對多關系

解決方法是添加第三張表,這個表稱為關聯表

。多對多關系可以分解成原表和關聯表之間的兩個一對多關系。

技術分享

用SQLAlchemy實現圖中的關系。

registrations = db.Table(registrations,
      db.Column(student_id, db.Integer,        db.ForeignKey(students.id)),
db.Column(class_id, db.Integer, db.ForeignKey(classes.id))
)
class Student(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name 
= db.Column(db.String) classes = db.relationship(Class, secondary=registrations, backref=db.backref(students, lazy=dynamic), lazy=dynamic) class Class(db.Model): id = db.Column(db.Integer, primary_key = True) name = db.Column(db.String)

多對多關系仍使用定義一對多關系的db.relationship() 方法進行定義,但在多對多關系中,必須把secondary 參數設為關聯表。多對多關系可以在任何一個類中定義,backref 參數會處理好關系的另一側。關聯表就是一個簡單的表,不是模型,SQLAlchemy 會自動接管這個表。

自引用關系

如果關系中的兩側都在同一個表中,這種關系稱為自引用關系。

高級多對多關系

使用多對多關系時,往往需要存儲所聯兩個實體之間的額外信息。對用戶之間的關註來說,可以存儲用戶關註另一個用戶的日期,這樣就能按照時間順序列出所有關註者。這種
信息只能存儲在關聯表中,但是在之前實現的學生和課程之間的關系中,關聯表完全是由SQLAlchemy 掌控的內部表。

為了能在關系中處理自定義的數據,我們必須提升關聯表的地位,使其變成程序可訪問的模型。

app/models/user.py:關註關聯表的模型實現

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.ForegnKey(users.id),primary_key = True)
    timestamp = db.Column(db.DateTime,default = datetime.utcnow)

app/models/user.py:使用兩個一對多關系實現的多對多關系

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 模型中為所有可能的操作定義輔助方法

app/models.py:關註關系的輔助方法

 #關註關系的輔助方法
    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(follow_id = user.id).first() is not None

    def is_followed(self,user):
        return self.followers.filter_by(follow_id = user.id).first() is not None

二、在資料頁中顯示關註者

app/templates/user.html:在用戶資料頁上部添加關註信息

{% extends "base.html" %}
{% import "_macros.html" as macros %}

{% block title %}微博 - {{ user.username }}{% endblock %}

{% block page_content %}
<div class="page-header">
    <img class="img-rounded profile-thumbnail" src="{{ user.gravatar(size=256) }}">
    <div class="profile-header">
        <h1>{{ user.username }}</h1>
        {% if user.name or user.location %}
        <p>
            {% if user.name %}{{ user.name }}<br>{% endif %}
            {% if user.location %}
                From <a href="http://maps.google.com/?q={{ user.location }}">{{ user.location }}</a><br>
            {% 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>創建時間 {{ moment(user.member_since).format(‘L‘) }}. 最後訪問 {{ moment(user.last_seen).fromNow() }}.</p>
        <p>{{ user.posts.count() }} 博客文章.</p>
        <p>
               {% 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">關註</a>
                {% else %}
                <a href="{{ url_for(‘.unfollow‘, username=user.username) }}" class="btn btn-success">取消關註</a>
                {% endif %}
            {% endif %}
            <a href="{{ url_for(‘.followers‘, username=user.username) }}">關註者: <span class="badge">{{ user.followers.count() }}</span></a>
            <a href="{{ url_for(‘.followed_by‘, username=user.username) }}">被關註: <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">關註了你</span>
            {% endif %}
        </p>
        <p>
            {% if user == current_user %}
            <a class="btn btn-default" href="{{ url_for(‘.edit_profile‘) }}">編輯個人資料</a>
            {% endif %}
            {% if current_user.is_administrator() %}
            <a class="btn btn-danger" href="{{ url_for(‘.edit_profile_admin‘, id=user.id) }}">編輯個人資料 [管理員]</a>
            {% endif %}
        </p>
    </div>
</div>
<h3>Posts by {{ user.username }}</h3>
{% include ‘_posts.html‘ %}
{% if pagination %}
<div class="pagination">
    {{ macros.pagination_widget(pagination, ‘.user‘, username=user.username) }}
</div>
{% endif %}
{% endblock %}

基於python的web應用開發-添加關註者