08-Follower

这章将告诉你如何实现类似于Twitter和其他社交网络的“粉丝”功能。

在本章中,我将更多地使用应用的数据库。 我希望应用的用户能够轻松便捷地关注其他用户。

本章的GitHub链接为: Source, Diff, Zip

完善用户模型

首先我们列下要实现的用户操作:

  • 关注 - Follow

  • 取消关注 - UnFollow

  • 关注自己 - FollowSelf

  • follower数量 - FollowersCount

  • following数量 - FollowingCount

  • 关注的Posts - FollowingPosts 这个将被用在页面美化那章中的登陆后的IndexView显示

  • 判断是否被关注 - IsFollowedByUser

  • (*)创建Post - CreatePost 这个是我们为了方便创建数据加入的,和粉丝操作关系不大

Tip: 这里 Followers 可以通过 Gorm 的 Association("Followers")来实现, Following 好像不支持(不确定,看了几遍文档没有找到),不过这里我们一顿骚操作,自己来实现一下嘛

model/user.go

...
// Follow func
// follow someone usr_id other.id follow_id u.id
func (u *User) Follow(username string) error {
    other, err := GetUserByUsername(username)
    if err != nil {
        return err
    }
    return db.Model(other).Association("Followers").Append(u).Error
}

// Unfollow func
func (u *User) Unfollow(username string) error {
    other, err := GetUserByUsername(username)
    if err != nil {
        return err
    }
    return db.Model(other).Association("Followers").Delete(u).Error
}

// FollowSelf func
func (u *User) FollowSelf() error {
    return db.Model(u).Association("Followers").Append(u).Error
}

// FollowersCount func
func (u *User) FollowersCount() int {
    return db.Model(u).Association("Followers").Count()
}

// FollowingIDs func
func (u *User) FollowingIDs() []int {
    var ids []int
    rows, err := db.Table("follower").Where("follower_id = ?", u.ID).Select("user_id, follower_id").Rows()
    if err != nil {
        log.Println("Counting Following error:", err)
        return ids
    }
    defer rows.Close()
    for rows.Next() {
        var id, followerID int
        rows.Scan(&id, &followerID)
        ids = append(ids, id)
    }
    return ids
}

// FollowingCount func
func (u *User) FollowingCount() int {
    ids := u.FollowingIDs()
    return len(ids)
}

// FollowingPosts func
func (u *User) FollowingPosts() (*[]Post, error) {
    var posts []Post
    ids := u.FollowingIDs()
    if err := db.Preload("User").Order("timestamp desc").Where("user_id in (?)", ids).Find(&posts).Error; err != nil {
        return nil, err
    }
    return &posts, nil
}

// IsFollowedByUser func
func (u *User) IsFollowedByUser(username string) bool {
    user, _ := GetUserByUsername(username)
    ids := user.FollowingIDs()
    for _, id := range ids {
        if u.ID == id {
            return true
        }
    }
    return false
}

// CreatePost func
func (u *User) CreatePost(body string) error {
    post := Post{Body: body, UserID: u.ID}
    return db.Create(&post).Error
}
...

然后在 AddUser 的时候加入 FollowSelf, 即自己关注自己,方便在显示 Profile 页的时候,展示 FollowingPosts 将自己的 Post 也列进去

model/user.go

由于我们一开始的建立用户,没有加入 Follower 功能,我们重新初始化一遍数据

cmd/init_db\main.go

执行

然后查看 follower 表,里面就有数据了

08-01

说明: 如上图 user_id 表示用户, follower_id 表示关注者, bonfy(id:1) 关注者 只有自己, 而 rene(id:2) 关注者 有两位, 这也是 u1.Follow(u2.Username) 的执行结果

本小节 Diff

完善页面显示

增加 Follow and Unfollow 操作

controller/home.go

FollowUnfollow之后通过 Redirect 回到原来的页面

完善Profile页面

vm/profile.go

templates/content/profile.html

运行

08-02

说明: 这个是通过 rene 登陆之后访问 http://127.0.0.1:8888/user/bonfy 查看 bonfy 的profile, 由于 rene 没有 follow bonfy,可以点击 Follow 按钮,实现Follow操作

本小节 Diff

Last updated