mod:кастомный шаблонный фильтр для статистики
This commit is contained in:
@@ -45,9 +45,9 @@
|
||||
|
||||
{# ШАПКА и главное меню #}
|
||||
<nav id="main-navbar" class="navbar navbar-expand-lg mb-4">
|
||||
<div class="container">
|
||||
<div class="container p-0">
|
||||
<a class="navbar-brand" href="/">
|
||||
<img id="logo-img" class="logo-img" src=""
|
||||
<img id="logo-img" class="logo-img p-0 m-0" src=""
|
||||
data-src-light="{% static 'svg/logo-etpgrf-site-light.svg' %}"
|
||||
data-src-light-compact="{% static 'svg/logo-etpgrf-site-light-compact.svg' %}"
|
||||
data-src-dark="{% static 'svg/logo-etpgrf-site-dark.svg' %}"
|
||||
@@ -64,12 +64,12 @@
|
||||
{# Футер #}
|
||||
<footer class="footer mt-auto py-2 mt-4">
|
||||
<div class="container d-flex justify-content-between align-items-center">
|
||||
<span class="text-muted small nowrap">© Sergei Erjemin, 2025–{% now 'Y' %}.</span>
|
||||
<span class="text-muted small nowrap me-2">© Sergei Erjemin, 2025–{% now 'Y' %}.</span>
|
||||
|
||||
<span class="text-muted small nowrap"><i class="bi bi-tags me-1" title="Версия библиотеки etpgrf / Версия сайта"></i>v0.1.3 / v0.1.3</span>
|
||||
<nobr class="text-muted small mx-2"><i class="bi bi-tags me-1" title="Версия библиотеки etpgrf / Версия сайта"></i>v0.1.3 / v0.1.3</nobr>
|
||||
|
||||
{# Сводная статистика (HTMX) #}
|
||||
<span class="text-muted small" hx-get="{% url 'stats_summary' %}" hx-trigger="load">
|
||||
<span class="text-muted small ms-2" hx-get="{% url 'stats_summary' %}" hx-trigger="load">
|
||||
...
|
||||
</span>
|
||||
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
<span class="me-3" title="Просмотров">
|
||||
<i class="bi bi-eye me-1"></i>{{ views }}
|
||||
</span>
|
||||
<span class="me-3 nowrap" title="На вход обработано текстов/символов">
|
||||
<i class="bi bi-box-arrow-in-right me-1"></i>{{ processed }}/{{ chars_in }}
|
||||
</span>
|
||||
<span class="me-3" title="На выход получено символов">
|
||||
<i class="bi bi-box-arrow-right me-1"></i>{{ chars_out }}
|
||||
</span>
|
||||
<span class="nowrap" title="Скопировано в буфер текстов/символов">
|
||||
<i class="bi bi-clipboard-check me-1"></i>{{ copied }}/{{ chars_copied }}
|
||||
</span>
|
||||
{% load typograph_extras %}
|
||||
<nobr class="ms-3 float-end" title="Скопировано в буфер текстов/символов">
|
||||
<i class="bi bi-clipboard-check me-1"></i>{{ copied|humanize_num }} / {{ chars_copied|humanize_num }}
|
||||
</nobr>
|
||||
<nobr class="ms-3 float-end" title="На выход получено символов">
|
||||
<i class="bi bi-box-arrow-right me-1"></i>{{ chars_out|humanize_num }}
|
||||
</nobr>
|
||||
<nobr class="ms-3 float-end" title="На вход обработано текстов/символов">
|
||||
<i class="bi bi-box-arrow-in-right me-1"></i>{{ processed|humanize_num }} / {{ chars_in|humanize_num }}
|
||||
</nobr>
|
||||
<nobr class="ms-3 float-end" title="Просмотров">
|
||||
<i class="bi bi-eye me-1"></i>{{ views|humanize_num }}
|
||||
</nobr>
|
||||
|
||||
|
||||
|
||||
|
||||
45
etpgrf_site/typograph/templatetags/typograph_extras.py
Normal file
45
etpgrf_site/typograph/templatetags/typograph_extras.py
Normal file
@@ -0,0 +1,45 @@
|
||||
from django import template
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
register = template.Library()
|
||||
|
||||
@register.filter(name='humanize_num')
|
||||
def humanize_num(value):
|
||||
"""
|
||||
Форматирует число с тонкими пробелами в качестве разделителя тысяч
|
||||
и сокращает большие числа до M (миллионы) или k (тысячи).
|
||||
|
||||
Примеры:
|
||||
1234 -> 1 234
|
||||
1234567 -> 1,2M
|
||||
"""
|
||||
try:
|
||||
num = int(value)
|
||||
if num > 1_000_000_000:
|
||||
val = num / 1_000_000_000
|
||||
suffix = " B"
|
||||
elif num > 1_000_000:
|
||||
val = num / 1_000_000
|
||||
suffix = " M"
|
||||
elif num > 1_000:
|
||||
val = num / 1_000
|
||||
suffix = " k"
|
||||
else:
|
||||
# Больше 1B -- форматируем с пробелами
|
||||
return mark_safe(f"{num:,}".replace(",", " "))
|
||||
|
||||
# Форматируем float:
|
||||
# {:,.1f} - разделитель тысяч (запятая) и 1 знак после точки
|
||||
# 1234567.89 -> "1,234,567.9"
|
||||
formatted = f"{val:,.2f}"
|
||||
|
||||
# Меняем английскую запятую (разделитель тысяч) на тонкий пробел
|
||||
# Меняем английскую точку (десятичный разделитель) на запятую
|
||||
# Но тут проблема: replace делает все сразу.
|
||||
# "1,234.5" -> replace(",", " ") -> "1 234.5" -> replace(".", ",") -> "1 234,5"
|
||||
formatted = formatted.replace(",", " ").replace(".", ",")
|
||||
|
||||
return mark_safe(f"{formatted}{suffix}")
|
||||
|
||||
except (ValueError, TypeError):
|
||||
return value
|
||||
@@ -23,35 +23,28 @@ def index(request):
|
||||
|
||||
def get_stats_summary(request):
|
||||
"""Возвращает сводную статистику."""
|
||||
# Убираем try...except для отладки
|
||||
stats = DailyStat.objects.aggregate(
|
||||
views=Sum('index_views'),
|
||||
processed=Sum('process_requests'),
|
||||
copied=Sum('copy_count'),
|
||||
chars_in=Sum('chars_in'),
|
||||
chars_out=Sum('chars_out'),
|
||||
chars_copied=Sum('chars_copied')
|
||||
)
|
||||
# print("Aggregated stats:", stats) # DEBUG
|
||||
try:
|
||||
stats = DailyStat.objects.aggregate(
|
||||
views=Sum('index_views'),
|
||||
processed=Sum('process_requests'),
|
||||
copied=Sum('copy_count'),
|
||||
chars_in=Sum('chars_in'),
|
||||
chars_out=Sum('chars_out'),
|
||||
chars_copied=Sum('chars_copied')
|
||||
)
|
||||
|
||||
# Функция для форматирования чисел с сокращениями (M, k)
|
||||
def format_large_number(num):
|
||||
if num > 1_000_000:
|
||||
return f"{num / 1_000_000:.3f}M".replace(".", ",")
|
||||
elif num > 1_000:
|
||||
return f"{num / 1_000:.2f}k".replace(".", ",")
|
||||
return str(num)
|
||||
context = {
|
||||
'views': stats['views'] or 0,
|
||||
'processed': stats['processed'] or 0,
|
||||
'copied': stats['copied'] or 0,
|
||||
'chars_in': stats['chars_in'] or 0,
|
||||
'chars_out': stats['chars_out'] or 0,
|
||||
'chars_copied': stats['chars_copied'] or 0,
|
||||
}
|
||||
|
||||
context = {
|
||||
'views': f"{(stats['views'] or 0):,}".replace(",", " "),
|
||||
'processed': f"{(stats['processed'] or 0):,}".replace(",", " "),
|
||||
'copied': f"{(stats['copied'] or 0):,}".replace(",", " "),
|
||||
'chars_in': format_large_number(stats['chars_in'] or 0),
|
||||
'chars_out': format_large_number(stats['chars_out'] or 0),
|
||||
'chars_copied': format_large_number(stats['chars_copied'] or 0),
|
||||
}
|
||||
|
||||
return render(request, 'typograph/stats_summary.html', context)
|
||||
return render(request, 'typograph/stats_summary.html', context)
|
||||
except Exception:
|
||||
return HttpResponse("...")
|
||||
|
||||
|
||||
@require_POST
|
||||
|
||||
Reference in New Issue
Block a user