97 lines
2.9 KiB
Python
97 lines
2.9 KiB
Python
from typing import Optional
|
||
from django.http import HttpRequest
|
||
from .models import PageView, Visitor
|
||
from django.utils import timezone
|
||
|
||
from typing import Type
|
||
from django.db.models import Model, QuerySet
|
||
|
||
|
||
def get_client_ip(request: HttpRequest) -> str:
|
||
"""Получаем реальный IP клиента."""
|
||
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
|
||
if x_forwarded_for:
|
||
ip = x_forwarded_for.split(',')[0]
|
||
else:
|
||
ip = request.META.get('REMOTE_ADDR', '')
|
||
return ip
|
||
|
||
|
||
def should_track_request(request: HttpRequest) -> bool:
|
||
"""Определяем, нужно ли отслеживать запрос."""
|
||
client_ip = get_client_ip(request)
|
||
path = request.path
|
||
|
||
# Игнорируемые пути
|
||
ignored_paths = [
|
||
'/static/', '/admin/', '/index.php', '/status.php',
|
||
'/cron', '/remote.php', '/ocs', '/apps/', '/custom_apps/',
|
||
]
|
||
|
||
# Игнорируемые IP (Docker сети)
|
||
docker_ips = [
|
||
'192.168.64.1', '192.168.65.1',
|
||
'172.17.0.1', '172.18.0.1', '172.19.0.1',
|
||
]
|
||
|
||
if any(path.startswith(p) for p in ignored_paths):
|
||
return False
|
||
if client_ip in docker_ips:
|
||
return False
|
||
|
||
return True
|
||
|
||
|
||
def track_page_view(request: HttpRequest) -> None:
|
||
"""Основная функция отслеживания просмотров."""
|
||
if not should_track_request(request):
|
||
return
|
||
|
||
try:
|
||
# Сохраняем просмотр страницы
|
||
PageView.objects.create(
|
||
url=request.path,
|
||
ip_address=get_client_ip(request),
|
||
user_agent=request.META.get('HTTP_USER_AGENT', '')[:500],
|
||
referer=request.META.get('HTTP_REFERER', '')[:500],
|
||
)
|
||
|
||
# Обновляем статистику посетителя
|
||
ip = get_client_ip(request)
|
||
visitor, created = Visitor.objects.get_or_create(
|
||
ip_address=ip,
|
||
defaults={
|
||
'first_visit': timezone.now(),
|
||
'last_visit': timezone.now()
|
||
}
|
||
)
|
||
|
||
if not created:
|
||
visitor.last_visit = timezone.now()
|
||
visitor.visit_count += 1
|
||
visitor.save()
|
||
|
||
except Exception as e:
|
||
# В продакшене лучше использовать логирование
|
||
print(f"Error tracking page view: {e}")
|
||
|
||
|
||
def get_published_queryset(model_class, order_by: str = '-time_create'):
|
||
"""
|
||
Возвращает QuerySet опубликованных записей для модели.
|
||
|
||
Args:
|
||
model_class: Класс модели Django
|
||
order_by: Поле для сортировки
|
||
|
||
Returns:
|
||
QuerySet или пустой список, если поле is_published отсутствует
|
||
"""
|
||
if hasattr(model_class, 'is_published'):
|
||
return model_class.objects.filter(is_published=True).order_by(order_by)
|
||
return model_class.objects.none()
|
||
|
||
|
||
|
||
|