使用Redis构建简易社交网站(2)-处理用户关系

目的

本文目的:实现用户关注和取消关注功能。(完整代码附在文章末尾)

相关知识

在我之前的文章 《使用Redis构建简易社交网站(1)-创建用户与动态界面》中提到了如何实现简易社交网站中创建新用户和创建新动态功能。

那这篇文章将教会你掌握:1.redis基本命令,2.python基本命令。

redis基本命令

zscore:返回有序集合中指定成员的分值。

conn = redis.Redis()
conn.zscore("testzset", "member1")
conn.zscore("testzset", "not_exists_member")

testzset内容如下:

执行结果:

100.0
None

zadd:将成员加入到有序集合中,并确保其在正确的位置上。

conn = redis.Redis()
conn.zadd("testzset", "member2", 3)
conn.zadd("testzset", "member1", 2)
conn.zadd("testzset", "member3", 1)

执行后:

member3
member1
member2

执行结果:111

hincrby:为哈希中指定域的值增加增量 increment,用于统计。

conn = redis.Redis()
conn.hincrby("testhash", "field1", 1)

执行前:

{'field1': '1'}

执行后:

{'field1': '2'}

zrem:从有序集合中移除指定成员。

conn = redis.Redis()
conn.zrem("testzset", "member1")

执行前:

member3
member1
member2

执行后:

member3
member2

执行结果:1

pipeline:将多条命令按照先后顺序放进一个队列中,一般配合execute一同使用,原子性(atomic)地执行队列里的命令。

conn = redis.Redis()
pipe = conn.pipeline(True) # 事务开始
pipe.incr("counter")
pipe.incr("counter")
pipe.incr("counter")
pipe.execute() # 事务执行

执行结果:[1, 2, 3],通过下标即可获取对应命令的执行结果。

python基本命令

使用格式化拼接字符串:

"My name is %s, I'm %i years old"%('educoder', 2)

执行结果:"My name is educoder, I'm 2 years old"

返回当前时间的时间戳。

  1. time.time()

将字符串转换为整型数据:

  1. int("1")

执行结果:1

取一个数的相反数:

  1. a = 1
  2. b = -a
  3. print b

执行结果:-1

实战例题

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

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

编写 unfollow(uid, other_uid) 函数,实现取消关注的功能,具体参数与要求如下:

  • 方法参数uid为当前用户编号,other_uid为被取消关注的用户编号;
  • 避免重复取消关注的实现:如果被关注的用户编号已经不在当前用户的关注列表following:{uid}中,则不重复取消关注,直接返回None
  • 删除关注关系的实现:使用事务一次性提交:
    • 从当前用户的关注列表following:{uid}中移除被取消关注用户编号。
    • 从被取消关注用户的粉丝列表中followers:{other_uid}移除当前用户编号。
  • 修改统计数据的实现:若关系删除成功,则使用事务一次性提交:
    • 将当前用户详情user:{uid}中的关注数following1
    • 将被取消关注用户详情user:{other_uid}中的粉丝数followers1
  • 返回执行结果的实现:返回True

注意: 关注列表和粉丝列表均为有序集合,存储成员时,分值均为当前时间戳; 用户详情为上一关中创建的哈希结构。

测试输入:

  1. 9
  2. 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
 

 code.py

#code.py
#-*- 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

read.py

#read.py
#-*- coding:utf-8 -*-

import os
import sys
import time
import redis
import pprint
from code import *

conn = redis.Redis()
retry_time = 0
while True:
    try:
        conn.ping()
        break
    except redis.exceptions.ConnectionError:
        os.system("redis-server > /dev/null 2>&1 &")
        retry_time += 1
        if retry_time > 3:
            break

pipe = conn.pipeline(True)
pipe.delete("users", "user:id")
keys = conn.keys("user:*") + conn.keys("followers:*") + conn.keys("following:*")
for key in keys:
    pipe.delete(key)
pipe.execute()

# 创建测试数据
join_str = " "
for i in xrange(10):
    login_name = "test_user%i"%(i+1)
    real_name = join_str.join(login_name.split("_")).capitalize()
    create_user(login_name, real_name)

uid = int(sys.stdin.readline().strip())
other_uid = int(sys.stdin.readline().strip())

print "测试 follow 方法..."
print "用户 %i 关注 用户 %i"%(uid, other_uid)
f_result = follow(uid, other_uid)
print "关注结果: " + str(f_result)
print "用户 %i 的关注列表内容为: %s"%(uid, str(conn.zrange("following:%i"%(uid), 0, -1)))
print "用户 %i 的粉丝列表内容为: %s"%(other_uid, str(conn.zrange("followers:%i"%(other_uid), 0, -1)))
uid_info = conn.hgetall("user:%i"%(uid))
uid_info.pop("last_signup", "404")
other_uid_info = conn.hgetall("user:%i"%(other_uid))
other_uid_info.pop("last_signup", "404")
print "用户 %i 的用户详情为: %s"%(uid, str(uid_info))
print "用户 %i 的用户详情为: %s"%(other_uid, str(other_uid_info))
print

print "用户 %i 再次关注 用户 %i"%(uid, other_uid)
oth_f_result = follow(uid, other_uid)
print "关注结果: " + str(oth_f_result)
print

print "测试 unfollow 方法..."
print "用户 %i 取消关注 用户 %i"%(uid, other_uid)
unf_result = unfollow(uid, other_uid)
print "取消关注结果: " + str(unf_result)
print "用户 %i 的关注列表内容为: %s"%(uid, str(conn.zrange("following:%i"%(uid), 0, -1)))
print "用户 %i 的粉丝列表内容为: %s"%(other_uid, str(conn.zrange("followers:%i"%(other_uid), 0, -1)))
uid_info = conn.hgetall("user:%i"%(uid))
uid_info.pop("last_signup", "404")
other_uid_info = conn.hgetall("user:%i"%(other_uid))
other_uid_info.pop("last_signup", "404")
print "用户 %i 的用户详情为: %s"%(uid, str(uid_info))
print "用户 %i 的用户详情为: %s"%(other_uid, str(other_uid_info))
print

print "用户 %i 再次取消关注 用户 %i"%(uid, other_uid)
oth_unf_result = unfollow(uid, other_uid)
print "取消关注结果: " + str(oth_unf_result)

pipe = conn.pipeline(True)
pipe.delete("users", "user:id")
keys = conn.keys("user:*") + conn.keys("followers:*") + conn.keys("following:*")
for key in keys:
    pipe.delete(key)
pipe.execute()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/216774.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

代币化:2024年的金融浪潮预示着什么?

自“TradFi”领袖到加密专家,各方预测代币化机会高达数十万亿。虽然已有引人注目的用例,但与未来几年可能在链上转移的大量数字化资产相比,这些仅是冰山一角。 代币化何时会变为洪流?什么阻碍了其发展? 今年10月&…

网络初识:局域网广域网网络通信基础

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、局域网LAN是什么?二、广域网是什么:三. IP地址四.端口号五.认识协议5.1五元组 总结 前言 一、局域网LAN是什么? 局域网…

JVM简单了解内存溢出

JVM oracle官网文档:https://docs.oracle.com/en/java/javase/index.html 什么是JVM JVM(Java Virtual Machine)原名Java虚拟机,是一个可以执行Java字节码的虚拟计算机。它的作用是在不同平台上实现Java程序的跨平台运行,即使在不同的硬件…

【驾校管理系统源码】基于Springboot+Vue个人驾校预约管理系统

🍅 简介:500精品计算机源码学习 🍅 欢迎点赞 👍 收藏 ⭐留言 📝 文末获取源码 目录 一、以下学习内容欢迎领取: Eclipse运行教学: Idea运行项目教学: Pycharm调试项目教学&#…

用Python手把手教你实现一个爬虫(含前端界面)

目录 前言爬虫基本原理使用Python的requests库发送HTTP请求使用BeautifulSoup库解析HTML页面使用PyQt5构建前端界面实现一个完整的爬虫程序结语 前言 随着互联网的飞速发展,再加上科技圈的技术翻天覆地的革新,互联网上每天都会产生海量的数据&#xff…

数据库更换版本

目录 0.前言 1.官网下载MySQL 2.配置初始化文件my.ini 3.初始化MySQL 4.安装mysql服务并启动修改密码 5.配置环境变量​编辑 0.前言 心累,为了完成实验,必须使用8.0版本导致我更新版本的时候,把sqlyog干崩溃了,什么版本不兼…

分清社保、医保、新农合

社保中的大头是养老保险,从上图可知成都每个月最低849.2元,对于底层人民来说价格不菲,但对应的医保才107元,那么能不能只交医保呢? 分三种情况: 1、如果我们购买的是城镇职工医疗保险,公司买的也…

<JavaEE> 单例模式的两种实现:“饿汉模式”和“懒汉模式”

目录 一、单例模式概述 二、“饿汉模式”实现单例模式 三、“懒汉模式”实现单例模式 3.1 单线程下的“懒汉模式” 3.2 多线程下的“懒汉模式” 一、单例模式概述 1)什么是单例模式? 单例模式是一种设计模式。 单例模式可以保证某个类在程序中只存…

电源自动测试系统| 电源模块温度循环怎么测试?

在一些应用领域,电源模块会在极端环境温度条件下工作。为了确保电源在高低温环境下可以正常运行,满足设备需求,需要对电源模块进行温度循环测试。 温度循环测试是指电源模块经过升温、保温、降温等多次循环试验来检测其在温度变化下的耐热性、…

解决在Linux中进行redis的主从复制时出现的从机可以获取到主机的信息,主机获取不到从机的信息~

主机: 从机1: 从机2: 出现上述的原因是我在redis.conf中设置了密码,那么就导致了我在进行主从复制时,需要进行密码验证,然后我在网上查阅了很多资料,有的说让在从机中指定密码,有的说…

HarmonyOS开发上手

首先献出开发官网地址 (https://developer.harmonyos.com/cn/develop/) 本文内容 基础入门内容介绍安装DevEco StudioDevEco Studio常用功能介绍项目工程结构详解 1. 基础入门内容介绍 应用开发流程 在正式开始之前还需要了解一些有关的基础概念 方舟…

出现数据库出现没有时间格式的错误,实体类Date类型不对导致时间报错

目录 报错现场解决办法java与mysql中的日期类型及二者的对应关系和使用场景 报错现场 数据库最早时间为2023年1月1日,前端查询后却出现2022年12月31日的数据 数据库时间类型为date swagger接口测试 解决办法 讲until的Date改成sql类的Date,就可以了…

茄子科技张韶全:跨多云大数据平台DataCake在OceanBase的实践

11 月 16 日,OceanBase 在北京顺利举办 2023 年度发布会,正式宣布:将持续践行“一体化”产品战略,为关键业务负载打造一体化数据库。其中,在“数字化转型升级实践专场”,我们有幸邀请到了茄子科技大数据技术…

MYSQL练题笔记-聚合函数-各赛事的用户注册率

一、题目相关内容 1)相关的表 2)题目 3)帮助理解题目的示例,提供返回结果的格式 二、自己初步的理解 有两张不同左右的表,用户表和赛事注册表。然后解题。 1.各种赛事的用户注册百分率 各种赛事的意味着通过contes…

ES6 import

这里 import 的文件是项目内自己 export 的对象,并非 package.json 里引用的包。 后者的打包策略和配置有关。 原理:彻底理解JavaScript ES6中的import和export - 知乎

深度学习(五):pytorch迁移学习之resnet50

1.迁移学习 迁移学习是一种机器学习方法,它通过将已经在一个任务上学习到的知识应用到另一个相关任务上,来改善模型的性能。迁移学习可以解决数据不足或标注困难的问题,同时可以加快模型的训练速度。 迁移学习的核心思想是将源领域的知识迁…

YOLOv8改进有效涨点 | 2023 | SPD-Conv空间深度转换卷积(高效空间编码技术)

一、本文介绍 本文给大家带来的改进内容是SPD-Conv(空间深度转换卷积)技术。SPD-Conv是一种创新的空间编码技术,它通过更有效地处理图像数据来改善深度学习模型的表现。SPD-Conv的基本概念:它是一种将图像空间信息转换为深度信息…

Leetcode每日一题学习训练——Python版(从二叉搜索树到更大和树)

版本说明 当前版本号[20231204]。 版本修改说明20231204初版 目录 文章目录 版本说明目录从二叉搜索树到更大和树理解题目代码思路参考代码 原题可以点击此 1038. 从二叉搜索树到更大和树 前去练习。 从二叉搜索树到更大和树 给定一个二叉搜索树 root (BST),请…

【React设计】React企业级设计模式

Image Source : https://bugfender.com React是一个强大的JavaScript库,用于构建用户界面。其基于组件的体系结构和构建可重用组件的能力使其成为许多企业级应用程序的首选。然而,随着应用程序的规模和复杂性的增长,维护和扩展变得更加困难。…

FCRP第二题

【题目要求】 数据库中有一张地区数据统计表,但是并不规则 ,记录类似于,225100:02:3:20160725是一串代码,以:分割,第1位为地区代码,第2位为分类代码,第3位为数量,第4位为…
最新文章