Files
fangke/server/tracker/services/stats.py
T

37 lines
1.8 KiB
Python
Raw Normal View History

from datetime import datetime, time, timedelta
from django.utils import timezone
from tracker.models import DailyStat, Event, VisitSession, Visitor
2026-09-15 14:50:09 +08:00
def daily_counts(site, date) -> dict:
"""四指标共享口径(site=None 聚合全部站点)。所有指标排除爬虫。
日界取 TIME_ZONE(Asia/Shanghai)自然日:make_aware(datetime.combine(date, time.min))。
口径:pv/uv 均从事件表统计(排除 is_bot),uv=distinct visitor,与 pv 同源;
2026-09-15 14:50:09 +08:00
sessions 按会话 started_at 落入当日且访客非爬虫;new_visitors 按 Visitor.first_seen_at 落入当日。
refresh_daily 落库与 dashboard 今日实时位共用此函数,防两处口径漂移(Task8 审查结论)。
"""
day_start = timezone.make_aware(datetime.combine(date, time.min))
day_end = day_start + timedelta(days=1)
2026-09-15 14:50:09 +08:00
ev = Event.objects.filter(is_bot=False,
occurred_at__gte=day_start, occurred_at__lt=day_end)
vs = VisitSession.objects.filter(visitor__is_bot=False,
started_at__gte=day_start, started_at__lt=day_end)
vis = Visitor.objects.filter(is_bot=False,
first_seen_at__gte=day_start, first_seen_at__lt=day_end)
if site is not None:
ev = ev.filter(site=site)
vs = vs.filter(site=site)
vis = vis.filter(site=site)
return {"pv": ev.count(),
"uv": ev.values("visitor").distinct().count(),
"sessions": vs.count(),
"new_visitors": vis.count()}
def refresh_daily(site, date) -> DailyStat:
"""重算某站点某自然日的聚合(幂等,update_or_create)。指标口径见 daily_counts。"""
obj, _ = DailyStat.objects.update_or_create(site=site, date=date,
2026-09-15 14:50:09 +08:00
defaults=daily_counts(site, date))
return obj