first init statistics
This commit is contained in:
parent
8b0d78f25e
commit
ab11148521
22 changed files with 3227 additions and 2 deletions
184
app/statistic/views.py
Normal file
184
app/statistic/views.py
Normal file
|
@ -0,0 +1,184 @@
|
|||
from django.views.generic import TemplateView
|
||||
from django.db.models import Count, Q
|
||||
from django.utils import timezone
|
||||
from datetime import datetime
|
||||
from bird.models import FallenBird, Bird, BirdStatus, Circumstance
|
||||
from .models import StatisticIndividual, StatisticYearGroup, StatisticTotalGroup, StatisticConfiguration
|
||||
|
||||
|
||||
class StatisticView(TemplateView):
|
||||
template_name = 'statistic/overview.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
# Aktuelles Jahr
|
||||
current_year = timezone.now().year
|
||||
|
||||
# Lade aktive Konfiguration
|
||||
try:
|
||||
config = StatisticConfiguration.objects.get(is_active=True)
|
||||
except StatisticConfiguration.DoesNotExist:
|
||||
# Fallback: Erstelle Standard-Konfiguration wenn keine vorhanden
|
||||
config = StatisticConfiguration.objects.create(
|
||||
is_active=True,
|
||||
show_year_total_patients=True,
|
||||
show_total_patients=True,
|
||||
show_percentages=True,
|
||||
show_absolute_numbers=True
|
||||
)
|
||||
|
||||
context['config'] = config
|
||||
context['current_year'] = current_year
|
||||
|
||||
# 1. Jahresstatistik
|
||||
if config.show_year_total_patients:
|
||||
patients_this_year = FallenBird.objects.filter(
|
||||
date_found__year=current_year
|
||||
).count()
|
||||
context['patients_this_year'] = patients_this_year
|
||||
|
||||
# Lade aktive Jahres-Gruppen und berechne Statistiken
|
||||
year_groups = StatisticYearGroup.objects.filter(is_active=True).order_by('order')
|
||||
year_summary = []
|
||||
|
||||
for group in year_groups:
|
||||
status_ids = list(group.status_list.values_list('id', flat=True))
|
||||
year_count = FallenBird.objects.filter(
|
||||
date_found__year=current_year,
|
||||
status__id__in=status_ids
|
||||
).count()
|
||||
|
||||
# Berechne Prozentanteil
|
||||
year_percentage = (year_count / patients_this_year * 100) if patients_this_year > 0 else 0
|
||||
|
||||
year_summary.append({
|
||||
'name': group.name,
|
||||
'count': year_count,
|
||||
'percentage': round(year_percentage, 1),
|
||||
'color': group.color,
|
||||
'order': group.order
|
||||
})
|
||||
|
||||
context['year_summary'] = year_summary
|
||||
|
||||
# 2. Gesamtstatistik
|
||||
if config.show_total_patients:
|
||||
total_patients = FallenBird.objects.count()
|
||||
context['total_patients'] = total_patients
|
||||
|
||||
# Lade aktive Gesamt-Gruppen und berechne Statistiken
|
||||
total_groups = StatisticTotalGroup.objects.filter(is_active=True).order_by('order')
|
||||
total_summary = []
|
||||
|
||||
for group in total_groups:
|
||||
status_ids = list(group.status_list.values_list('id', flat=True))
|
||||
total_count = FallenBird.objects.filter(
|
||||
status__id__in=status_ids
|
||||
).count()
|
||||
|
||||
# Berechne Prozentanteil
|
||||
total_percentage = (total_count / total_patients * 100) if total_patients > 0 else 0
|
||||
|
||||
total_summary.append({
|
||||
'name': group.name,
|
||||
'count': total_count,
|
||||
'percentage': round(total_percentage, 1),
|
||||
'color': group.color,
|
||||
'order': group.order
|
||||
})
|
||||
|
||||
context['total_summary'] = total_summary
|
||||
|
||||
# 3. Statistik pro Vogelart (Individuen - dynamisch basierend auf Konfiguration)
|
||||
individual_groups = StatisticIndividual.objects.filter(is_active=True).order_by('order')
|
||||
context['statistic_individuals'] = individual_groups
|
||||
|
||||
bird_stats = []
|
||||
for bird in Bird.objects.all():
|
||||
fallen_birds = FallenBird.objects.filter(bird=bird)
|
||||
total_count = fallen_birds.count()
|
||||
|
||||
if total_count > 0: # Nur Vögel anzeigen, die auch Patienten haben
|
||||
bird_data = {
|
||||
'name': bird.name,
|
||||
'species': bird.species or 'Unbekannt',
|
||||
'total': total_count,
|
||||
'groups': []
|
||||
}
|
||||
|
||||
# Berechne Statistiken für jede konfigurierte Individuen-Gruppe
|
||||
for group in individual_groups:
|
||||
status_ids = list(group.status_list.values_list('id', flat=True))
|
||||
group_count = fallen_birds.filter(status__id__in=status_ids).count()
|
||||
group_percentage = (group_count / total_count) * 100 if total_count > 0 else 0
|
||||
|
||||
bird_data['groups'].append({
|
||||
'name': group.name,
|
||||
'color': group.color,
|
||||
'count': group_count,
|
||||
'percentage': round(group_percentage, 1),
|
||||
'order': group.order
|
||||
})
|
||||
|
||||
bird_stats.append(bird_data)
|
||||
|
||||
# Sortiere nach Gesamtanzahl (absteigend)
|
||||
bird_stats.sort(key=lambda x: x['total'], reverse=True)
|
||||
|
||||
# Berechne Balkenbreiten basierend auf der höchsten Vogelart für bessere Visualisierung
|
||||
if bird_stats:
|
||||
max_count = bird_stats[0]['total'] # Höchste Anzahl (wird 100% der Balkenbreite)
|
||||
|
||||
for bird in bird_stats:
|
||||
# Berechne Balkenbreite für Gesamtanzahl
|
||||
total_bar_width = (bird['total'] / max_count) * 100 if max_count > 0 else 0
|
||||
bird['total_bar_width'] = f"{total_bar_width:.1f}".replace(',', '.')
|
||||
|
||||
# Berechne Balkenbreiten für jede Gruppe
|
||||
for group_data in bird['groups']:
|
||||
group_bar_width = (group_data['count'] / max_count) * 100 if max_count > 0 else 0
|
||||
group_data['bar_width'] = f"{group_bar_width:.1f}".replace(',', '.')
|
||||
|
||||
context['bird_stats'] = bird_stats
|
||||
|
||||
# 4. Fundumstände-Statistiken (unverändert)
|
||||
# Fundumstände für aktuelles Jahr
|
||||
circumstances_this_year = FallenBird.objects.filter(
|
||||
date_found__year=current_year,
|
||||
find_circumstances__isnull=False
|
||||
).values('find_circumstances__name', 'find_circumstances__description').annotate(
|
||||
count=Count('id')
|
||||
).order_by('-count')
|
||||
|
||||
# Fundumstände für alle Jahre
|
||||
circumstances_all_time = FallenBird.objects.filter(
|
||||
find_circumstances__isnull=False
|
||||
).values('find_circumstances__name', 'find_circumstances__description').annotate(
|
||||
count=Count('id')
|
||||
).order_by('-count')
|
||||
|
||||
# Formatiere Daten für Tortendiagramme
|
||||
def format_circumstances_data(circumstances_data):
|
||||
total = sum(item['count'] for item in circumstances_data)
|
||||
formatted_data = []
|
||||
colors = [
|
||||
'#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF',
|
||||
'#FF9F40', '#FF6384', '#C9CBCF', '#4BC0C0', '#FF6384'
|
||||
]
|
||||
|
||||
for i, item in enumerate(circumstances_data):
|
||||
name = item['find_circumstances__name'] or item['find_circumstances__description']
|
||||
percentage = round((item['count'] / total) * 100, 1) if total > 0 else 0
|
||||
formatted_data.append({
|
||||
'name': name,
|
||||
'count': item['count'],
|
||||
'percentage': percentage,
|
||||
'color': colors[i % len(colors)]
|
||||
})
|
||||
return formatted_data, total
|
||||
|
||||
context['circumstances_this_year'], context['circumstances_this_year_total'] = format_circumstances_data(circumstances_this_year)
|
||||
context['circumstances_all_time'], context['circumstances_all_time_total'] = format_circumstances_data(circumstances_all_time)
|
||||
|
||||
return context
|
Loading…
Add table
Add a link
Reference in a new issue