如何实现类似Snapchat的连续答题Streak功能?
如何实现类似Snapchat的连续答题Streak功能?
需求规则
- 用户每24小时至少提交1条答案,无论提交多少条,Streak维持当前数值;
- 若超过24小时未提交,Streak清零;
- 清零后再次提交,Streak从1开始,后续若在距上次提交的24小时内提交,Streak递增1。
当前Django实现问题
你将current_streak存储在ModelAnswer模型中(每个答案对应一个streak值),且核心逻辑用自然日区间判断提交行为,导致同一天内多次提交会重复递增streak,不符合“维持streak”的规则,同时streak作为用户全局属性,存储在答案模型中设计不合理。
当前模型代码
class ModelAnswer(BaseModel): questions = models.ForeignKey( to=Questions, on_delete=models.CASCADE ) answer = models.TextField() user = models.ForeignKey(User, on_delete=models.CASCADE) current_streak = models.PositiveIntegerField( null=True, blank=True, default=0, editable=False )
当前核心逻辑代码
def save(self, *args, **kwargs): today = timezone.now() yesterday = today - timedelta(days=1) print(today,yesterday) # get the categories created yesterday to maintain the streak answers_created_yesterday = ModelAnswer.objects.filter( Q(created_at__gte=yesterday), Q(created_at__lt=today), user=self.user ).order_by('-id').last() if answers_created_yesterday is not None: self.current_streak = answers_created_yesterday.current_streak + 1 else: self.current_streak = 1 print(self.current_streak) super(ModelAnswer, self).save(args, kwargs)
优化解决方案(Django)
1. 调整模型设计
将streak相关字段移到User模型中(streak是用户的全局属性):
from django.contrib.auth.models import AbstractUser from django.db import models class User(AbstractUser): current_streak = models.PositiveIntegerField(default=0) last_submission_time = models.DateTimeField(null=True, blank=True)
2. 修正提交逻辑
修改ModelAnswer的save方法,基于用户上次提交的时间差判断streak变化,避免同一周期内重复递增:
from django.utils import timezone from datetime import timedelta def save(self, *args, **kwargs): user = self.user now = timezone.now() # 获取用户最近的一条提交记录 last_answer = ModelAnswer.objects.filter(user=user).order_by('-created_at').first() if not last_answer: # 首次提交,streak设为1 user.current_streak = 1 else: time_since_last = now - last_answer.created_at if time_since_last > timedelta(hours=24): # 超过24小时未提交,重置streak user.current_streak = 1 else: # 检查本次提交是否是当前24小时周期内的第一次提交 has_recent_submission = ModelAnswer.objects.filter( user=user, created_at__gt=last_answer.created_at, created_at__lt=now ).exists() if not has_recent_submission: # 周期内首次提交,streak递增 user.current_streak += 1 # 更新用户的上次提交时间 user.last_submission_time = now user.save() # 保存当前答案 super().save(*args, **kwargs)
通用逻辑实现(伪代码/JavaScript)
如果不用Django,可通过以下逻辑计算streak:
// 假设userSubmissions是用户的提交记录数组,每个元素含createdAt时间戳 function calculateUserStreak(userSubmissions) { if (userSubmissions.length === 0) return 0; // 按提交时间倒序排序 userSubmissions.sort((a, b) => b.createdAt - a.createdAt); let streak = 1; let lastSubmitTime = userSubmissions[0].createdAt; const ONE_DAY = 24 * 60 * 60 * 1000; // 24小时的毫秒数 for (let i = 1; i < userSubmissions.length; i++) { const currentSubmitTime = userSubmissions[i].createdAt; const timeDiff = lastSubmitTime - currentSubmitTime; if (timeDiff > ONE_DAY) { // 超过24小时,streak中断 break; } // 检查是否跨了新的24小时周期 const cycleEnd = currentSubmitTime + ONE_DAY; if (lastSubmitTime > cycleEnd) { streak++; } lastSubmitTime = currentSubmitTime; } return streak; }
内容的提问来源于stack exchange,提问作者lord stock
相关产品推荐
相关产品推荐

