python / expert
Snippet
Django Eigene Template Tags mit Komplexer Datenaggregation
Dieses Snippet zeigt die Erstellung eines eigenen Django Inclusion-Tags, das komplexe Datenbank-Aggregation durchführt und strukturierte Daten an ein Template zur Darstellung übergibt. Das Tag verwendet Annotationen, um mehrere Metriken (Anzahl, Durchschnitt, Summe) in einer einzigen Datenbankabfrage zu berechnen, was N+1 Abfrageprobleme reduziert. Der Parameter takes_context=True ermöglicht den Zugriff auf anfrage-spezifische Daten für Berechtigungsfilterung.
snippet.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from django import templatefrom django.db.models import Count, Avg, Sumfrom django.utils.html import format_htmlregister = template.Library()@register.inclusion_tag('analytics/chart_data.html', takes_context=True)def render_category_analytics(context, queryset):"""Aggregates category data for chart rendering with filtering."""aggregated = (queryset.values('category__name', 'category__color').annotate(total_count=Count('id'),avg_rating=Avg('rating'),total_revenue=Sum('price')).order_by('-total_count'))chart_data = [{'label': item['category__name'],'color': item['category__color'],'datasets': [{'metric': 'Count', 'value': item['total_count'], 'formatted': f"{item['total_count']:,}"},{'metric': 'Avg Rating', 'value': round(item['avg_rating'] or 0, 2), 'formatted': f"{item['avg_rating']:.1f}" if item['avg_rating'] else 'N/A'},{'metric': 'Revenue', 'value': item['total_revenue'] or 0, 'formatted': f"${item['total_revenue']:,.2f}" if item['total_revenue'] else '$0.00'}]}for item in aggregated]return {'chart_data': chart_data, 'total_categories': len(chart_data)}
django
Erklärung
1
@register.inclusion_tag('analytics/chart_data.html', takes_context=True)
Decorator registriert die Funktion als Inclusion-Tag, das eine separate Template-Datei zum Rendern verwendet
2
queryset.values('category__name', 'category__color')
Verwendet values() um nach Kategorie-Beziehungsfeldern zu gruppieren und nur benötigte Spalten auszuwählen
3
.annotate(total_count=Count('id'), avg_rating=Avg('rating'), total_revenue=Sum('price'))
Führt Aggregation mit COUNT, AVG und SUM Operationen in einer einzigen Datenbankabfrage durch
4
chart_data = [{...} for item in aggregated]
List Comprehension transformiert rohe aggregierte Ergebnisse in ein chart-bereites strukturiertes Format
5
return {'chart_data': chart_data, 'total_categories': len(chart_data)}
Gibt ein Kontext-Wörterbuch zurück, das mit dem übergeordneten Kontext für das Template-Rendering zusammengeführt wird