Django中实现每日数据最大值与平均值展示的类及视图求助
Hey there! As someone new to Python and Django, I get that figuring out how to aggregate and display daily stats can feel overwhelming at first. Let’s walk through this step by step, starting with the simplest approach that doesn’t require extra models, then moving to a more scalable option if you need it later.
If your dataset isn’t huge (like hundreds of entries per day max), you can use Django’s built-in aggregation functions to calculate daily averages and max values directly when someone visits the stats page.
Step 1: Write the View
In your app’s views.py, add this function:
from django.db.models import Avg, Max, TruncDate from django.utils import timezone from django.shortcuts import render from .models import Entry def daily_stats(request): # Group entries by date, then compute averages and maxes for each field daily_data = Entry.objects.annotate( # Truncate the `time` field to just the date part for grouping date=TruncDate('time') ).values('date').annotate( # Calculate averages and maxes for each metric avg_inside=Avg('inside'), max_inside=Max('inside'), avg_outside=Avg('outside'), max_outside=Max('outside'), avg_gavg=Avg('gavg'), max_gavg=Max('gavg'), avg_ghigh=Avg('ghigh'), max_ghigh=Max('ghigh') ).order_by('-date') # Show newest dates first # Pass the stats to your template return render(request, 'daily_stats.html', {'daily_data': daily_data})
Step 2: Create a Template
Make a daily_stats.html file in your app’s templates folder to display the data:
<h1>Daily Temperature & G-Metric Stats</h1> <table style="border-collapse: collapse; width: 100%; margin-top: 20px;"> <thead> <tr style="border-bottom: 2px solid #ddd;"> <th style="padding: 8px; text-align: left;">Date</th> <th style="padding: 8px; text-align: right;">Avg Inside</th> <th style="padding: 8px; text-align: right;">Max Inside</th> <th style="padding: 8px; text-align: right;">Avg Outside</th> <th style="padding: 8px; text-align: right;">Max Outside</th> <th style="padding: 8px; text-align: right;">Avg Gavg</th> <th style="padding: 8px; text-align: right;">Max Gavg</th> <th style="padding: 8px; text-align: right;">Avg Ghigh</th> <th style="padding: 8px; text-align: right;">Max Ghigh</th> </tr> </thead> <tbody> {% for stats in daily_data %} <tr style="border-bottom: 1px solid #eee;"> <td style="padding: 8px;">{{ stats.date|date:"Y-m-d" }}</td> <td style="padding: 8px; text-align: right;">{{ stats.avg_inside|floatformat:2 }}</td> <td style="padding: 8px; text-align: right;">{{ stats.max_inside|floatformat:2 }}</td> <td style="padding: 8px; text-align: right;">{{ stats.avg_outside|floatformat:2 }}</td> <td style="padding: 8px; text-align: right;">{{ stats.max_outside|floatformat:2 }}</td> <td style="padding: 8px; text-align: right;">{{ stats.avg_gavg|floatformat:0 }}</td> <td style="padding: 8px; text-align: right;">{{ stats.max_gavg }}</td> <td style="padding: 8px; text-align: right;">{{ stats.avg_ghigh|floatformat:0 }}</td> <td style="padding: 8px; text-align: right;">{{ stats.max_ghigh }}</td> </tr> {% empty %} <tr> <td colspan="9" style="padding: 16px; text-align: center;">No data available yet. Check back after your first 5-minute entry!</td> </tr> {% endfor %} </tbody> </table>
Step 3: Add a URL
In your app’s urls.py, map the view to a URL so users can access it:
from django.urls import path from .views import daily_stats urlpatterns = [ # ... your other URLs go here path('daily-stats/', daily_stats, name='daily_stats'), ]
If you end up with thousands of entries per day, calculating stats on-the-fly might slow down your page. Instead, we can precompute and store daily stats in a separate model, then just query that model for display.
Step 1: Create a Daily Stats Model
Add this to your models.py:
from django.db import models from django.utils import timezone class DailyStats(models.Model): date = models.DateField(unique=True) # One entry per date avg_inside = models.FloatField() max_inside = models.FloatField() avg_outside = models.FloatField() max_outside = models.FloatField() avg_gavg = models.FloatField() max_gavg = models.IntegerField() avg_ghigh = models.FloatField() max_ghigh = models.IntegerField() class Meta: ordering = ['-date'] # Newest dates first def __str__(self): return f"Stats for {self.date}"
Don’t forget to run python manage.py makemigrations and python manage.py migrate to create the table.
Step 2: Write a Function to Compute & Save Stats
Add this function to your models.py (or a separate utils.py file):
from django.db.models import Avg, Max from .models import Entry, DailyStats from django.utils import timezone def calculate_daily_stats(target_date=None): # Default to yesterday if no date is provided if not target_date: target_date = timezone.now().date() - timezone.timedelta(days=1) # Get all entries from the target date daily_entries = Entry.objects.filter(time__date=target_date) if not daily_entries.exists(): return # Skip if there's no data for the date # Compute the stats stats = daily_entries.aggregate( avg_inside=Avg('inside'), max_inside=Max('inside'), avg_outside=Avg('outside'), max_outside=Max('outside'), avg_gavg=Avg('gavg'), max_gavg=Max('gavg'), avg_ghigh=Avg('ghigh'), max_ghigh=Max('ghigh') ) # Save or update the stats (prevents duplicate entries) DailyStats.objects.update_or_create( date=target_date, defaults=stats )
Step 3: Automate the Calculation
You’ll want to run this function daily. For simplicity, you can use Django’s django-crontab package to set up a scheduled task:
- Install it:
pip install django-crontab - Add it to
INSTALLED_APPSinsettings.py - Add this to
settings.py:CRONJOBS = [ # Run at 1 AM every day to compute yesterday's stats ('0 1 * * *', 'yourapp.utils.calculate_daily_stats') ] - Run
python manage.py crontab addto activate the task.
Step 4: Update the View
Now your view can just fetch the precomputed stats, which is much faster:
from django.shortcuts import render from .models import DailyStats def daily_stats(request): daily_data = DailyStats.objects.all() return render(request, 'daily_stats.html', {'daily_data': daily_data})
The template from the first approach will work perfectly here—no changes needed!
Either approach will get you up and running. Start with the first one if you’re still learning, and switch to the second if you notice performance issues as your dataset grows.
内容的提问来源于stack exchange,提问作者Blake Russell

