How do I implement snap chat streak like feature?

Question:

I am failing to build logic regarding streak feature similar to Snapchat. Here is how streak gets counted in snapchat
problem is.
if the user adds a new data record once every 24 hours streak is one irrespective of how many records he/she adds and streak is 0 if he/she fails to add with in next time period and adds by +1 in next 24 hours timeframe from last record added.

Streak is actually based on user and answer if user adds answer than streak is maintained.

I tried this code in django but any help in any language will be valuable

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

    )

here is my main logic part this is not working as per required

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)
Asked By: nava

||

Answers:

Just because you said that help in any language will be valuable, I will be answering in English.

  1. You should have a DateTime field with your answer
  2. streak can be a Dict {"start":last_week, "current":whenever_check_function_runs"}
  3. Just access the last answer (order_by("-AnswerDate").last()) and calculate the delta with timezone.now() and show streak_count, if delta is less than 24 hours and set streak["current"] to timezone.now().
  4. You don’t need all the answers, you need the last answer from the user.
  5. If delta exceeds 24 hours, set streak["start"], streak["current"] to timezone.now()
  6. Return streak_count by calculating delta of (streak["start"], streak["current"]) +1

I hope it helps.

Answered By: user8559923

I’ve created a journaling app with a similar streak system.

The method I used was to add a last_answered field onto the user/profile model. Every time the user would upload a log, last_answered was set to the current time. Then, to ensure that the streak would not stay at (for example) 2 until they submitted the next post, a check is run every time the user viewed their streak to see if last_answered was more than 24 hours away.

in addition, as @Art pointed out in comments, the current_streak should be saved on the user/profile model.

To add the two fields onto the user model, you should extend the user model with a profile model like so:

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    last_answered = models.DateTimeField(null=True)
    streak = models.IntegerField(default=0)

Then every time the user views the streak–or if you want to save resources you can use the method @Art mentioned and run the function using celery–you should run this check

from datetime import datetime, timedelta

def update_streak(self):
    current = datetime.now()
    delta = current - self.last_answered

    if delta > timedelta(1)
        self.streak = 0
    return True

Of course you could also use your method, searching for the latest answer and testing what time it was submitted, but then you should be saving the exact time of submission onto the ModalAnswer.

Finally, when submitting, you should increment the streak. This function ensures that it’s a new day to make sure the user can’t abuse the streak by submitting a bunch of entries. If you want to simulate snapchat more closely, adjust the threshold of streak loss in the function above to something like 36 hours to give users a bit of leeway.

def save(self, *args, **kwargs):
    today = datetime.now().date()
    last_submitted = self.request.user.profile.last_answered
    delta = today - last_submitted.date()

    if delta > timedelta(1):
        self.request.user.profile.increment_streak()    

Then in the Profile modal:

def increment_streak():
    self.streak += 1

I just put the increment_streak in a seperate function out of habit but you can put it in the save function as well. Keep in mind, if you don’t have a profile model or something similar and plan to implement it, you’ll need to change up your user sign up model and forms.

One notable downside is that if the user decides to stay up at 11:59pm, technically they can increase their streak by 2 in the span of a few minutes.

Answered By: Redmac

after long trial and error I did this way:

today = timezone.now()
        yesterday = today - timedelta(days=1)

        # get the categories created yesterday to maintain the streak
        last_24_hours_entries = ModelAnswer.objects.filter(
            Q(created_at__gte=yesterday),
            Q(created_at__lt=today),
            user=self.user
        ).first()
        last_48_hours = today - timedelta(days=2)

        if last_24_hours_entries is None:
            last__48_hour_streak = ModelAnswer.objects.filter(
                Q(created_at__gte=last_48_hours),
                Q(created_at__lt=today),
                user=self.user
            ).last()
            if last__48_hour_streak is not None:
                self.current_streak = last__48_hour_streak.current_streak + 1
            else:
                self.current_streak = 1
        else:
            self.current_streak = last_24_hours_entries.current_streak
Answered By: nava
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.