使用Redis构建简单的社交网站

文章目录

  • 第1关:创建用户与动态
  • 第2关:处理用户关系
  • 第3关:状态与信息流


第1关:创建用户与动态

编程要求
在Begin-End区域编写 create_user(login_name, real_name) 函数,实现创建新用户的功能,具体参数与要求如下:

方法参数login_name为用户登录名,real_name为用户真名;
用户登录名预处理的实现:将用户登录名转换成全小写格式;
重名检测的实现:查询哈希键users中是否存在与用户登录名同名的域,若存在,则不允许重新创建该用户,返回None;
分配用户编号的实现:对计数器user:id递增1,并将递增后的值作为新用户的编号;
存储用户信息的实现:使用事务一次性提交:
存储登录名的实现:将用户登录名记录到哈希键users当中,值为该用户编号;
存储详情的实现:按照如下示意将用户信息存储到哈希键user:{id}中:

返回创建结果的实现:返回新创建用户的编号。
编写 create_post(uid, content) 函数,实现创建新动态的功能,具体参数与要求如下:

方法参数uid为发布动态的用户编号,content为要发布的动态内容;
用户合法性检测的实现:查找用户编号对应详情信息哈希user:{uid}是否存在login_name域,若存在,则记录,若不存在,则不允许创建新动态,返回None;
分配动态编号的实现:对计数器post:id递增1,并将递增后的值作为新动态的编号;
存储动态信息的实现:按照如下示意将动态信息存储到哈希键post:{id}中:

更新用户动态数的实现:为该用户编号对应的详情信息哈希user:{uid}中的posts域的值加1;
返回创建结果的实现:返回新创建动态的编号。
测试说明
平台会对你编写的代码进行测试:

测试输入:无;
预期输出:

测试 create_user 方法…
第一次创建登录名为 TestUser 的用户
创建的用户ID为: 1
当前分配的用户ID为: 1
创建的用户信息为: {‘login_name’: ‘testuser’, ‘posts’: ‘0’, ‘real_name’: ‘Test User’, ‘followers’: ‘0’, ‘following’: ‘0’, ‘id’: ‘1’}
第二次创建登录名为 TestUser 的用户
创建的用户ID为: None
当前分配的用户ID为: 1
测试 create_post 方法…
为用户 1 创建一条动态
创建的动态ID为: 1
当前分配的动态ID为: 1
创建的动态信息为: {‘content’: ‘First POST!’, ‘uid’: ‘1’, ‘user_name’: ‘testuser’, ‘id’: ‘1’}
对应用户信息中更新为: {‘login_name’: ‘testuser’, ‘posts’: ‘1’, ‘real_name’: ‘Test User’, ‘followers’: ‘0’, ‘following’: ‘0’, ‘id’: ‘1’}
为不存在的用户 9 创建一条动态
创建的动态ID为: None
开始你的任务吧,祝你成功!

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import re
import time
import redis

conn = redis.Redis()

# 创建新用户
def create_user(login_name, real_name):
    # 请在下面完成要求的功能
    #********* Begin *********#
    login_name = login_name.lower()
    if conn.hget("users", login_name):
        return None

    uid = conn.incr("user:id")
    pipe = conn.pipeline(True)
    pipe.hset("users", login_name, uid)
    pipe.hmset("user:%i"%(uid), {
        'login_name': login_name,
        'id': uid,
        'real_name': real_name,
        'followers': 0,
        'following': 0,
        'posts': 0,
        'last_signup': time.time(),
    })
    pipe.execute()

    return uid
    #********* End *********#

# 为用户创建新动态
def create_post(uid, content):
    # 请在下面完成要求的功能
    #********* Begin *********#
    pipe = conn.pipeline(True)
    pipe.hget("user:%i"%(uid), 'login_name')
    pipe.incr("post:id")
    login_name, pid = pipe.execute()

    if not login_name:
        return None

    pipe.hmset("post:%i"%(pid), {
        'id': pid,
        'uid': uid,
        'content': content,
        'posted': time.time(),
        'user_name': login_name,
    })
    pipe.hincrby("user:%i"%(uid), 'posts')
    pipe.execute()

    return pid
    #********* End *********#

使用Redis构建简单的社交网站_第1张图片

第2关:处理用户关系

编程要求
在Begin-End区域编写 follow(uid, other_uid) 函数,实现关注用户的功能,具体参数与要求如下:

方法参数uid为当前用户编号,other_uid为被关注的用户编号;
避免重复关注的实现:如果被关注的用户编号已经在当前用户的关注列表following:{uid}中,则不重复关注,直接返回None;
建立关注关系的实现:使用事务一次性提交:
将被关注的用户编号加入到当前用户的关注列表following:{uid}中,分值为当前时间戳。
将当前用户编号加入到被关注用户的粉丝列表中followers:{other_uid},分值为当前时间戳。
修改统计数据的实现:若关系建立成功,则使用事务一次性提交:
将当前用户详情user:{uid}中的关注数following加1
将被关注用户详情user:{other_uid}中的粉丝数followers加1
返回执行结果的实现:返回True
编写 unfollow(uid, other_uid) 函数,实现取消关注的功能,具体参数与要求如下:

方法参数uid为当前用户编号,other_uid为被取消关注的用户编号;
避免重复取消关注的实现:如果被关注的用户编号已经不在当前用户的关注列表following:{uid}中,则不重复取消关注,直接返回None;
删除关注关系的实现:使用事务一次性提交:
从当前用户的关注列表following:{uid}中移除被取消关注用户编号。
从被取消关注用户的粉丝列表中followers:{other_uid}移除当前用户编号。
修改统计数据的实现:若关系删除成功,则使用事务一次性提交:
将当前用户详情user:{uid}中的关注数following减1
将被取消关注用户详情user:{other_uid}中的粉丝数followers减1
返回执行结果的实现:返回True
注意:
关注列表和粉丝列表均为有序集合,存储成员时,分值均为当前时间戳;
用户详情为上一关中创建的哈希结构。

测试说明
平台会对你编写的代码进行测试:

测试输入:

9
4
预期输出:

测试 follow 方法…
用户 9 关注 用户 4
关注结果: True
用户 9 的关注列表内容为: [‘4’]
用户 4 的粉丝列表内容为: [‘9’]
用户 9 的用户详情为: {‘login_name’: ‘test_user9’, ‘posts’: ‘0’, ‘real_name’: ‘Test user9’, ‘followers’: ‘0’, ‘following’: ‘1’, ‘id’: ‘9’}
用户 4 的用户详情为: {‘login_name’: ‘test_user4’, ‘posts’: ‘0’, ‘real_name’: ‘Test user4’, ‘followers’: ‘1’, ‘following’: ‘0’, ‘id’: ‘4’}
用户 9 再次关注 用户 4
关注结果: None
测试 unfollow 方法…
用户 9 取消关注 用户 4
取消关注结果: True
用户 9 的关注列表内容为: []
用户 4 的粉丝列表内容为: []
用户 9 的用户详情为: {‘login_name’: ‘test_user9’, ‘posts’: ‘0’, ‘real_name’: ‘Test user9’, ‘followers’: ‘0’, ‘following’: ‘0’, ‘id’: ‘9’}
用户 4 的用户详情为: {‘login_name’: ‘test_user4’, ‘posts’: ‘0’, ‘real_name’: ‘Test user4’, ‘followers’: ‘0’, ‘following’: ‘0’, ‘id’: ‘4’}
用户 9 再次取消关注 用户 4
取消关注结果: None
开始你的任务吧,祝你成功!

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import re
import time
import redis

conn = redis.Redis()

# 关注用户
def follow(uid, other_uid):
    # 请在下面完成要求的功能
    #********* Begin *********#
    fkey1 = "following:%s"%(uid)
    fkey2 = "followers:%s"%(other_uid)

    if conn.zscore(fkey1, other_uid):
        return None

    now = time.time()
    pipe = conn.pipeline(True)
    pipe.zadd(fkey1, other_uid, now)
    pipe.zadd(fkey2, uid, now)
    following, followers = pipe.execute()

    pipe.hincrby("user:%s"%(uid), 'following', int(following))
    pipe.hincrby("user:%s"%(other_uid), 'followers', int(followers))
    pipe.execute()

    return True
    #********* End *********#

# 取消关注
def unfollow(uid, other_uid):
    # 请在下面完成要求的功能
    #********* Begin *********#
    fkey1 = "following:%s"%(uid)
    fkey2 = "followers:%s"%(other_uid)

    if not conn.zscore(fkey1, other_uid):
        return None

    pipe = conn.pipeline(True)
    pipe.zrem(fkey1, other_uid)
    pipe.zrem(fkey2, uid)
    following, followers = pipe.execute()

    pipe.hincrby("user:%s"%(uid), 'following', -int(following))
    pipe.hincrby("user:%s"%(other_uid), 'followers', -int(followers))
    pipe.execute()

    return True
    #********* End *********#

# 创建新用户
def create_user(login_name, real_name):
    login_name = login_name.lower()
    if conn.hget("users", login_name):
        return None

    uid = conn.incr("user:id")
    pipe = conn.pipeline(True)
    pipe.hset("users", login_name, uid)
    pipe.hmset("user:%i"%(uid), {
        'login_name': login_name,
        'id': uid,
        'real_name': real_name,
        'followers': 0,
        'following': 0,
        'posts': 0,
        'last_signup': time.time(),
    })
    pipe.execute()

    return uid

# 为用户创建新动态
def create_post(uid, content):
    pipe = conn.pipeline(True)
    pipe.hget("user:%i"%(uid), 'login_name')
    pipe.incr("post:id")
    login_name, pid = pipe.execute()

    if not login_name:
        return None

    pipe.hmset("post:%i"%(pid), {
        'id': pid,
        'uid': uid,
        'content': content,
        'posted': time.time(),
        'user_name': login_name,
    })
    pipe.hincrby("user:%i"%(uid), 'posts')
    pipe.execute()

    return pid

使用Redis构建简单的社交网站_第2张图片

第3关:状态与信息流

编程要求
在Begin-End区域编写 get_home_timeline(uid) 函数,实现获得主页时间线的功能,具体参数与要求如下:

方法参数uid为要获取主页时间线的用户编号;
获取动态编号的实现:从存储用户主页时间线的有序集合home:{uid}中按照分值递减的顺序取出所有成员;
获取动态详情的实现:遍历动态编号,使用事务一次性获取每个动态编号对应动态详情哈希键post:{pid}的所有域-值对;
返回主页时间线的实现:返回事务执行的结果。
编写 post(uid, content) 函数,实现发布动态并将动态推送给粉丝的功能,具体参数与要求如下:

方法参数uid为要发布动态的用户编号,content为要发布的动态内容;
发布动态的实现:调用第一关中实现的create_post方法,并接收返回的动态编号,若发布失败,则取消发布,返回None;
获取发布时间的实现:从新发布的动态编号对应的动态详情哈希键post:{pid}中获取posted域;
更新个人主页的实现:将新发布的动态编号存储到个人主页有序集合键profile:{uid}中,分值为转为浮点数后的发布时间;
更新粉丝主页时间线的实现:遍历用户的粉丝列表followers:{uid},将新发布的动态编号存储到每个粉丝的主页时间线的有序集合home:{follower_id}中,分值为转为浮点数后的发布时间;
返回发布结果的实现:返回新发布的动态编号。
测试说明
平台会对你编写的代码进行测试:

测试输入:4;
预期输出:

用户 4 关注 用户 1
关注结果: True
测试 post 方法…
创建动态: 1
创建动态: 2
用户 1 的动态列表: [‘2’, ‘1’]
用户 4 的主页时间线动态编号: [‘2’, ‘1’]
测试 get_home_timeline 方法…
用户 4 的主页时间线: [{‘content’: ‘NEW post from user 1!!!’, ‘uid’: ‘1’, ‘user_name’: ‘test_user1’, ‘id’: ‘2’}, {‘content’: ‘This is the first post from user 1’, ‘uid’: ‘1’, ‘user_name’: ‘test_user1’, ‘id’: ‘1’}]
开始你的任务吧,祝你成功!

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import re
import time
import redis

conn = redis.Redis()

# 获得主页时间线
def get_home_timeline(uid, page=1, count=30):
    # 请在下面完成要求的功能
    #********* Begin *********#
    post_ids = conn.zrevrange("home:%s"%(uid), 0, -1)

    pipe = conn.pipeline(True)
    for pid in post_ids:
        pipe.hgetall("post:%s"%(pid))

    return pipe.execute()
    #********* End *********#

# 发布动态并将动态推送给粉丝
def post(uid, content):
    # 请在下面完成要求的功能
    #********* Begin *********#
    pid = create_post(uid, content)
    if not pid:
        return None

    posted = conn.hget("post:%s"%(pid), "posted")
    conn.zadd("profile:%s"%(uid), pid, float(posted))
    followers = conn.zrange("followers:%s"%(uid), 0, -1)

    pipe = conn.pipeline(False)
    for follower in followers:
        pipe.zadd("home:%s"%(follower), pid, float(posted))
    pipe.execute()

    return pid
    #********* End *********#

# 关注用户
def follow(uid, other_uid):
    fkey1 = "following:%s"%(uid)
    fkey2 = "followers:%s"%(other_uid)

    if conn.zscore(fkey1, other_uid):
        return None

    now = time.time()
    pipe = conn.pipeline(True)
    pipe.zadd(fkey1, other_uid, now)
    pipe.zadd(fkey2, uid, now)
    following, followers = pipe.execute()

    posts = conn.zrevrange("profile:%s"%(other_uid), 0, 100, withscores=True)
    if posts:
        pipe.zadd("home:%s"%(uid), **dict(posts))

    pipe.hincrby("user:%s"%(uid), 'following', int(following))
    pipe.hincrby("user:%s"%(other_uid), 'followers', int(followers))
    pipe.execute()

    return True

# 取消关注
def unfollow(uid, other_uid):
    fkey1 = "following:%s"%(uid)
    fkey2 = "followers:%s"%(other_uid)

    if not conn.zscore(fkey1, other_uid):
        return None

    pipe = conn.pipeline(True)
    pipe.zrem(fkey1, other_uid)
    pipe.zrem(fkey2, uid)
    following, followers = pipe.execute()

    posts = conn.zrevrange("profile:%s"%(other_uid), 0, -1)
    if posts:
        pipe.zrem("home:%s"%(uid), *posts)

    pipe.hincrby("user:%s"%(uid), 'following', -int(following))
    pipe.hincrby("user:%s"%(other_uid), 'followers', -int(followers))
    pipe.execute()

    return True

# 创建新用户
def create_user(login_name, real_name):
    login_name = login_name.lower()
    if conn.hget("users", login_name):
        return None

    uid = conn.incr("user:id")
    pipe = conn.pipeline(True)
    pipe.hset("users", login_name, uid)
    pipe.hmset("user:%i"%(uid), {
        'login_name': login_name,
        'id': uid,
        'real_name': real_name,
        'followers': 0,
        'following': 0,
        'posts': 0,
        'last_signup': time.time(),
    })
    pipe.execute()

    return uid

# 为用户创建新动态
def create_post(uid, content):
    pipe = conn.pipeline(True)
    pipe.hget("user:%i"%(uid), 'login_name')
    pipe.incr("post:id")
    login_name, pid = pipe.execute()

    if not login_name:
        return None

    pipe.hmset("post:%i"%(pid), {
        'id': pid,
        'uid': uid,
        'content': content,
        'posted': time.time(),
        'user_name': login_name,
    })
    pipe.hincrby("user:%i"%(uid), 'posts')
    pipe.execute()

    return pid


使用Redis构建简单的社交网站_第3张图片


你可能感兴趣的:(redis,数据库,缓存)