利用redis的bitmap实现用户签到功能
一、场景需求
适用场景如签到送积分、签到领取奖励等,大致需求如下:
- 比如签到1天送1积分,连续签到2天送2积分,3天送3积分,3天以上均送3积分等。
- 如果连续签到中断,则重置计数,每月初重置计数。
- 显示用户某个月的签到次数和首次签到时间。
- 在日历控件上展示用户每月签到情况,可以切换年月显示……等等。
二、代码
以下代码没有积分逻辑,只有签到
import datetime import redis class Redis(object): def __init__(self): self.redis_store = redis.Redis( host="127.0.0.1", port="6379", db="8" ) class RedisSignIn(Redis): @staticmethod def GetDaliySignKey(time=datetime.datetime.now()): # 拼接redis的key bitmap_key_daily_sign = "daily_sign_{date}" return bitmap_key_daily_sign.format(date=time.date()) def UserDailySign(self, session): user_id = session.get("user") if not user_id: print( "验证失败") return if self.UserDaliySignByUserId(user_id): rec = self.GetSignRecordByUserId(user_id, 7) l = len(rec.split('0')[0]) print(l) # 连续签到 if l > 1: pass if l > 6: pass return # 获取每月的签到记录 def GetUserDailySignRecordMonthly(self, session): user_id = session.get("user") if not user_id: print( "验证失败") return res = self.GetSignRecordByUserId(user_id) print(int(res, 2)) # 二进制数据转换为10进制,拿到的10进制数返回到前端,前端再解析成二进制数进行判断 return int(res, 2) def GetSignRecordByUserId(self, user_id, days=30): # 开启管道模拟事务 with self.redis_store.pipeline(True) as p: for i in range(days): # 获取key对应值的二进制表示中的某位的值 p = p.getbit(self.GetDaliySignKey(datetime.datetime.now() - datetime.timedelta(days=i)), user_id) # execute返回命令执行结果列表 res = p.execute() # res是一个[1,0,0,0...]的列表 print(res) # 转成字符串的二进制 return ''.join([str(x) for x in res]) # 通过user_id用户做每日签到 def UserDaliySignByUserId(self, user_id): if self.GetDailySignByUserId(user_id): print( "今天您已签到") return key = self.GetDaliySignKey() # key就是签到日期,将该user_id在key对应的位置上设置为1,表示签到了 self.redis_store.setbit(key, user_id, 1) # 设置key的过期时间 self.redis_store.expire(key, 60 * 60 * 24 * 30) return True # 通过user_id获取用户每日签到信息 def GetDailySignByUserId(self, user_id): return self.redis_store.getbit(self.GetDaliySignKey(), user_id) if __name__ == '__main__': session={"user":1003} sign=RedisSignIn() sign.UserDailySign(session) sign.GetUserDailySignRecordMonthly(session)