refactor: stats 提取共享 daily_counts
refresh_daily 四指标口径提取为模块级 daily_counts(site, date), site=None 时聚合全部站点,为 dashboard 今日实时位复用做准备 (Task8 审查结论:防两处口径漂移)。语义不变,既有 stats 测试全绿。 Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -3,24 +3,34 @@ from django.utils import timezone
|
|||||||
from tracker.models import DailyStat, Event, VisitSession, Visitor
|
from tracker.models import DailyStat, Event, VisitSession, Visitor
|
||||||
|
|
||||||
|
|
||||||
def refresh_daily(site, date) -> DailyStat:
|
def daily_counts(site, date) -> dict:
|
||||||
"""重算某站点某自然日的聚合(幂等,update_or_create)。
|
"""四指标共享口径(site=None 聚合全部站点)。所有指标排除爬虫。
|
||||||
|
|
||||||
日界取 TIME_ZONE(Asia/Shanghai)自然日:make_aware(datetime.combine(date, time.min))。
|
日界取 TIME_ZONE(Asia/Shanghai)自然日:make_aware(datetime.combine(date, time.min))。
|
||||||
口径:pv/uv 均从事件表统计(排除 is_bot),uv=distinct visitor,与 pv 同源;
|
口径:pv/uv 均从事件表统计(排除 is_bot),uv=distinct visitor,与 pv 同源;
|
||||||
sessions 按会话 started_at 落入当日且访客非爬虫;new_visitors 按 Visitor.first_seen_at 落入当日(同样排除爬虫访客,四指标口径统一)。
|
sessions 按会话 started_at 落入当日且访客非爬虫;new_visitors 按 Visitor.first_seen_at 落入当日。
|
||||||
|
refresh_daily 落库与 dashboard 今日实时位共用此函数,防两处口径漂移(Task8 审查结论)。
|
||||||
"""
|
"""
|
||||||
day_start = timezone.make_aware(datetime.combine(date, time.min))
|
day_start = timezone.make_aware(datetime.combine(date, time.min))
|
||||||
day_end = day_start + timedelta(days=1)
|
day_end = day_start + timedelta(days=1)
|
||||||
pv = Event.objects.filter(site=site, is_bot=False,
|
ev = Event.objects.filter(is_bot=False,
|
||||||
occurred_at__gte=day_start, occurred_at__lt=day_end).count()
|
occurred_at__gte=day_start, occurred_at__lt=day_end)
|
||||||
uv = Event.objects.filter(site=site, is_bot=False, occurred_at__gte=day_start,
|
vs = VisitSession.objects.filter(visitor__is_bot=False,
|
||||||
occurred_at__lt=day_end).values("visitor").distinct().count()
|
started_at__gte=day_start, started_at__lt=day_end)
|
||||||
sessions = VisitSession.objects.filter(site=site, visitor__is_bot=False,
|
vis = Visitor.objects.filter(is_bot=False,
|
||||||
started_at__gte=day_start,
|
first_seen_at__gte=day_start, first_seen_at__lt=day_end)
|
||||||
started_at__lt=day_end).count()
|
if site is not None:
|
||||||
new_v = Visitor.objects.filter(site=site, is_bot=False, first_seen_at__gte=day_start,
|
ev = ev.filter(site=site)
|
||||||
first_seen_at__lt=day_end).count()
|
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,
|
obj, _ = DailyStat.objects.update_or_create(site=site, date=date,
|
||||||
defaults={"pv": pv, "uv": uv, "sessions": sessions, "new_visitors": new_v})
|
defaults=daily_counts(site, date))
|
||||||
return obj
|
return obj
|
||||||
|
|||||||
Reference in New Issue
Block a user