Nutrition apps are evolving.
What used to be a simple meal log or calorie counter is now becoming something much more useful: a system that helps people understand their habits, stay consistent, and make better decisions over time.
That shift matters.
A single check-in tells you what happened today.
A weekly summary tells you whether behavior is actually changing.
In this article, we’ll build a Weekly Nutrition Summary API in Django REST Framework. The goal is not just to count records, but to turn daily nutrition logs into actionable insight.
By the end, you’ll have an endpoint that gives users a clear weekly view of:
- how many days they checked in
- how many meals they completed
- how much water they drank
- how often they met their calorie target
- their current and longest streaks
- a daily breakdown for dashboards and charts
This is the kind of feature that makes a nutrition app feel more like a product and less like a form.
Why this feature matters
Most health and habit-tracking apps collect data, but too few translate that data into meaningful feedback.
That’s the difference between logging and learning.
A weekly summary layer gives your app:
- better retention
- stronger user engagement
- more useful progress tracking
- a foundation for charts, gamification, and recommendations
It also creates a cleaner product story:
Users don’t just check in — they get insight back.
What we’ll build
We’ll assume you already have:
- a
DailyNutritionCheckInmodel - a
UserStreakmodel - authentication set up in Django REST Framework
We’ll build:
- a weekly summary API view
- a route for the endpoint
- a response structure that supports both dashboards and analytics
Step 1: Make sure your daily nutrition log exists
The weekly summary depends on daily data. If you don’t already have a check-in model, here’s a clean version to build from:
from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
class DailyNutritionCheckIn(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='nutrition_checkins')
log_date = models.DateField(default=timezone.localdate)
breakfast_completed = models.BooleanField(default=False)
lunch_completed = models.BooleanField(default=False)
dinner_completed = models.BooleanField(default=False)
water_intake_ml = models.PositiveIntegerField(default=0)
met_calorie_target = models.BooleanField(default=False)
notes = models.TextField(blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
unique_together = ('user', 'log_date')
ordering = ['-log_date']
def __str__(self):
return f"{self.user.username} - {self.log_date}"
Why this structure works
This model gives you one record per user per day. That is important because a summary layer works best when the underlying data is normalized and predictable.
The unique_together constraint prevents duplicate daily logs, which keeps weekly calculations accurate.
Step 2: Keep streak tracking in place
If you already have a streak model, reuse it. If not, you can use this:
class UserStreak(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='streak')
current_streak = models.PositiveIntegerField(default=1)
longest_streak = models.PositiveIntegerField(default=1)
last_logged_date = models.DateField(default=timezone.localdate)
def __str__(self):
return f"{self.user.username} - {self.current_streak} Day Streak"
Why this matters
Streaks help turn passive tracking into habit formation.
A weekly summary becomes more powerful when it includes:
- consistency metrics
- progress indicators
- habit momentum
That’s what keeps users coming back.
Step 3: Build the weekly summary view
Now we’ll create the API endpoint that reads the past 7 days of check-ins and returns a structured summary.
Add this to views.py:
from datetime import timedelta
from django.utils import timezone
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status
from .models import DailyNutritionCheckIn, UserStreak
class WeeklyNutritionSummaryView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request):
today = timezone.localdate()
week_start = today - timedelta(days=6)
checkins = DailyNutritionCheckIn.objects.filter(
user=request.user,
log_date__range=[week_start, today]
).order_by('log_date')
streak, _ = UserStreak.objects.get_or_create(user=request.user)
breakfast_count = checkins.filter(breakfast_completed=True).count()
lunch_count = checkins.filter(lunch_completed=True).count()
dinner_count = checkins.filter(dinner_completed=True).count()
calorie_target_count = checkins.filter(met_calorie_target=True).count()
total_water = sum(checkin.water_intake_ml for checkin in checkins)
average_water = round(total_water / checkins.count(), 2) if checkins.exists() else 0
daily_summary = [
{
"log_date": checkin.log_date,
"breakfast_completed": checkin.breakfast_completed,
"lunch_completed": checkin.lunch_completed,
"dinner_completed": checkin.dinner_completed,
"water_intake_ml": checkin.water_intake_ml,
"met_calorie_target": checkin.met_calorie_target,
"notes": checkin.notes,
}
for checkin in checkins
]
return Response({
"week_start": week_start,
"week_end": today,
"checkins_count": checkins.count(),
"breakfast_completed_count": breakfast_count,
"lunch_completed_count": lunch_count,
"dinner_completed_count": dinner_count,
"calorie_target_days": calorie_target_count,
"total_water_intake_ml": total_water,
"average_water_intake_ml": average_water,
"current_streak": streak.current_streak,
"longest_streak": streak.longest_streak,
"daily_summary": daily_summary,
}, status=status.HTTP_200_OK)
Step 4: Understand the logic
This view does three important things:
1. It defines a fixed 7-day window
today = timezone.localdate()
week_start = today - timedelta(days=6)
This ensures the summary always covers the last 7 days, including today.
2. It pulls only the authenticated user’s logs
checkins = DailyNutritionCheckIn.objects.filter(
user=request.user,
log_date__range=[week_start, today]
)
That means the summary is private and personalized.
3. It converts raw logs into useful metrics
Instead of returning raw database rows only, it computes:
- meal completion counts
- calorie target days
- total hydration
- average hydration
- streak data
That’s the move from data collection to insight delivery.
Step 5: Add the URL route
Next, connect the view in your urls.py:
from django.urls import path
from .views import WeeklyNutritionSummaryView
urlpatterns = [
path('api/weekly-summary/', WeeklyNutritionSummaryView.as_view(), name='weekly-summary'),
]
Step 6: Example response
Here’s what the API response might look like:
{
"week_start": "2025-06-01",
"week_end": "2025-06-07",
"checkins_count": 5,
"breakfast_completed_count": 4,
"lunch_completed_count": 5,
"dinner_completed_count": 3,
"calorie_target_days": 4,
"total_water_intake_ml": 9200,
"average_water_intake_ml": 1840,
"current_streak": 5,
"longest_streak": 8,
"daily_summary": [
{
"log_date": "2025-06-01",
"breakfast_completed": true,
"lunch_completed": true,
"dinner_completed": false,
"water_intake_ml": 1800,
"met_calorie_target": true,
"notes": "Good day"
}
]
}
Why this response format is useful
This response is intentionally split into two layers:
- summary metrics
- daily breakdown
That makes it flexible enough for:
- dashboard cards
- progress bars
- charts
- habit calendars
- mobile app views
A good API should not only answer a question.
It should give the frontend enough structure to build a useful experience.
Step 7: Improve it with aggregation later
The version above is clear and readable, which is great for a first implementation.
If you want to optimize it later, you can move more of the computation into database-level aggregation using:
CountSumAvg
That becomes useful if your dataset grows or if you expect many users to hit the summary endpoint frequently.
Example:
from django.db.models import Count, Sum, Avg
This allows the database to do more work instead of Python looping through the records.
For most early-stage apps, the simpler implementation is perfectly fine.
Step 8: Think about product value, not just code
This feature is more than a backend endpoint.
It changes how your app communicates value.
A weekly nutrition summary helps users answer questions like:
- Am I staying consistent?
- Which meals do I skip most often?
- Am I drinking enough water?
- Is my streak improving?
- What does my week actually look like?
That kind of feedback is what turns an app into a habit engine.
From a product perspective, that’s important because insight creates stickiness.
Optional next steps
Once this feature is in place, you can extend it in a few strong directions:
Add caching
Cache the weekly summary briefly to reduce repeated computation.
Add charts
Use the daily breakdown for line charts, bar charts, or a weekly heatmap.
Add badge logic
Reward users for:
- 7-day streaks
- full hydration weeks
- consistent meal completion
Add recommendations
Use the weekly summary to suggest:
- better hydration habits
- meal timing improvements
- smarter calorie planning
That’s where the app starts feeling intelligent.
Conclusion
Building a weekly nutrition summary is one of those features that sounds small but changes the product in a meaningful way.
Instead of just collecting check-ins, your app starts turning behavior into insight.
That matters because the best health apps don’t just ask users to log data. They help users understand themselves better.
With Django REST Framework, the implementation is straightforward:
- model your daily logs
- track streaks
- create a summary API
- return both totals and daily breakdowns
That gives you a strong foundation for dashboards, motivation, and future intelligence features.
If you’re building a nutrition or habit-tracking app, this is a feature worth adding early.
Top comments (0)