Оптимизировал просмотры страниц
This commit is contained in:
parent
a406614a06
commit
5a9c0bbcc6
@ -45,6 +45,9 @@ X_FRAME_OPTIONS = 'ALLOW-FROM https://metrika.yandex.ru'
|
|||||||
# ОБЯЗАТЕЛЬНО укажите ваши домены
|
# ОБЯЗАТЕЛЬНО укажите ваши домены
|
||||||
ALLOWED_HOSTS = os.getenv('DJANGO_ALLOWED_HOSTS', 'localhost,127.0.0.1').split(',')
|
ALLOWED_HOSTS = os.getenv('DJANGO_ALLOWED_HOSTS', 'localhost,127.0.0.1').split(',')
|
||||||
|
|
||||||
|
# Исключения для отслеживания
|
||||||
|
EXCLUDED_IPS = os.getenv('EXCLUDED_IPS', 'localhost,127.0.0.1').split(',')
|
||||||
|
|
||||||
# Важно для работы за прокси
|
# Важно для работы за прокси
|
||||||
if not DEBUG:
|
if not DEBUG:
|
||||||
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
# blog/signals.py
|
|
||||||
from django.db.models.signals import post_save
|
from django.db.models.signals import post_save
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from .models import Article
|
from .models import Article
|
||||||
|
|||||||
@ -96,7 +96,6 @@ class ArticleDetailView(MenuContextMixin, BreadcrumbMixin, DetailView):
|
|||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
"""Обработка формы комментария."""
|
"""Обработка формы комментария."""
|
||||||
self.object = self.get_object()
|
self.object = self.get_object()
|
||||||
print("POST data:", request.POST)
|
|
||||||
|
|
||||||
if not request.user.is_authenticated:
|
if not request.user.is_authenticated:
|
||||||
messages.error(request, "❌ Только авторизованные пользователи могут оставлять комментарии.")
|
messages.error(request, "❌ Только авторизованные пользователи могут оставлять комментарии.")
|
||||||
@ -106,7 +105,6 @@ class ArticleDetailView(MenuContextMixin, BreadcrumbMixin, DetailView):
|
|||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
|
|
||||||
parent_id = form.cleaned_data.get('parent_id')
|
parent_id = form.cleaned_data.get('parent_id')
|
||||||
print(f"parent_id from cleaned_data: {parent_id}")
|
|
||||||
parent = None
|
parent = None
|
||||||
|
|
||||||
if parent_id:
|
if parent_id:
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
from .models import PageView, Visitor
|
from .services import track_page_view
|
||||||
from django.utils import timezone
|
import logging
|
||||||
from django.db import transaction
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class CSPMiddleware:
|
class CSPMiddleware:
|
||||||
@ -20,45 +22,7 @@ class PageViewMiddleware:
|
|||||||
def __call__(self, request):
|
def __call__(self, request):
|
||||||
# Игнорируем статические файлы и админку
|
# Игнорируем статические файлы и админку
|
||||||
if not request.path.startswith('/static/') and not request.path.startswith('/admin/'):
|
if not request.path.startswith('/static/') and not request.path.startswith('/admin/'):
|
||||||
self.track_page_view(request)
|
track_page_view(request)
|
||||||
|
|
||||||
response = self.get_response(request)
|
response = self.get_response(request)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def track_page_view(self, request):
|
|
||||||
try:
|
|
||||||
with transaction.atomic():
|
|
||||||
# Сохраняем просмотр страницы
|
|
||||||
PageView.objects.create(
|
|
||||||
url=request.path,
|
|
||||||
ip_address=self.get_client_ip(request),
|
|
||||||
user_agent=request.META.get('HTTP_USER_AGENT', ''),
|
|
||||||
referer=request.META.get('HTTP_REFERER', '')
|
|
||||||
)
|
|
||||||
|
|
||||||
# Обновляем статистику посетителя
|
|
||||||
ip = self.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_client_ip(self, request):
|
|
||||||
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
|
|
||||||
@ -3,17 +3,6 @@ from django.views.generic.base import ContextMixin
|
|||||||
from .services import track_page_view
|
from .services import track_page_view
|
||||||
|
|
||||||
|
|
||||||
class PageViewTrackingMixin(ContextMixin):
|
|
||||||
"""
|
|
||||||
Миксин для отслеживания просмотров страниц.
|
|
||||||
Добавляет трекинг при вызове view.
|
|
||||||
"""
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
# Отслеживаем просмотр перед обработкой запроса
|
|
||||||
track_page_view(request)
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class MenuContextMixin(ContextMixin):
|
class MenuContextMixin(ContextMixin):
|
||||||
"""
|
"""
|
||||||
Миксин для добавления меню в контекст.
|
Миксин для добавления меню в контекст.
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from django.http import HttpRequest
|
from django.http import HttpRequest
|
||||||
|
from django.conf import settings
|
||||||
from .models import PageView, Visitor
|
from .models import PageView, Visitor
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
@ -28,14 +28,11 @@ def should_track_request(request: HttpRequest) -> bool:
|
|||||||
'/cron', '/remote.php', '/ocs', '/apps/', '/custom_apps/',
|
'/cron', '/remote.php', '/ocs', '/apps/', '/custom_apps/',
|
||||||
]
|
]
|
||||||
|
|
||||||
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):
|
if any(path.startswith(p) for p in ignored_paths):
|
||||||
return False
|
return False
|
||||||
if client_ip in docker_ips:
|
|
||||||
|
excluded_ips = getattr(settings, 'EXCLUDED_IPS', [])
|
||||||
|
if client_ip in excluded_ips:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|||||||
@ -16,7 +16,7 @@ from django.db.models import Count, QuerySet
|
|||||||
from django.contrib.auth.decorators import login_required, user_passes_test
|
from django.contrib.auth.decorators import login_required, user_passes_test
|
||||||
from django.views.decorators.http import require_GET, require_POST
|
from django.views.decorators.http import require_GET, require_POST
|
||||||
from django.views.generic import TemplateView, ListView, CreateView, UpdateView, DetailView
|
from django.views.generic import TemplateView, ListView, CreateView, UpdateView, DetailView
|
||||||
from .mixins import PageViewTrackingMixin, MenuContextMixin, BreadcrumbMixin
|
from .mixins import MenuContextMixin, BreadcrumbMixin
|
||||||
from .services import get_published_queryset, track_page_view
|
from .services import get_published_queryset, track_page_view
|
||||||
from typing import Any, Dict, Type
|
from typing import Any, Dict, Type
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
@ -26,7 +26,7 @@ from products.models import Order
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
class BasePageView(PageViewTrackingMixin, MenuContextMixin, TemplateView):
|
class BasePageView(MenuContextMixin, TemplateView):
|
||||||
"""
|
"""
|
||||||
Базовый класс для всех страниц сайта.
|
Базовый класс для всех страниц сайта.
|
||||||
Включает отслеживание просмотров и контекст меню.
|
Включает отслеживание просмотров и контекст меню.
|
||||||
@ -34,7 +34,7 @@ class BasePageView(PageViewTrackingMixin, MenuContextMixin, TemplateView):
|
|||||||
extra_context = {}
|
extra_context = {}
|
||||||
|
|
||||||
|
|
||||||
class BaseListView(PageViewTrackingMixin, MenuContextMixin, ListView):
|
class BaseListView(MenuContextMixin, ListView):
|
||||||
"""
|
"""
|
||||||
Базовый класс для всех страниц со списками объектов.
|
Базовый класс для всех страниц со списками объектов.
|
||||||
Включает отслеживание просмотров и контекст меню.
|
Включает отслеживание просмотров и контекст меню.
|
||||||
@ -194,14 +194,14 @@ class RecallListView(BaseListView, BreadcrumbMixin):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class ProfileView(LoginRequiredMixin, PageViewTrackingMixin, MenuContextMixin, BreadcrumbMixin, TemplateView):
|
class ProfileView(LoginRequiredMixin, MenuContextMixin, BreadcrumbMixin, TemplateView):
|
||||||
template_name = 'programmer/profile.html'
|
template_name = 'programmer/profile.html'
|
||||||
|
|
||||||
def get_breadcrumbs(self):
|
def get_breadcrumbs(self):
|
||||||
return [{'title': 'Профиль', 'url_name': None}]
|
return [{'title': 'Профиль', 'url_name': None}]
|
||||||
|
|
||||||
|
|
||||||
class RegisterView(PageViewTrackingMixin, MenuContextMixin, SuccessMessageMixin, BreadcrumbMixin, CreateView):
|
class RegisterView(MenuContextMixin, SuccessMessageMixin, BreadcrumbMixin, CreateView):
|
||||||
"""Регистрация нового пользователя"""
|
"""Регистрация нового пользователя"""
|
||||||
template_name = 'programmer/register.html'
|
template_name = 'programmer/register.html'
|
||||||
form_class = RegistrationForm
|
form_class = RegistrationForm
|
||||||
@ -240,7 +240,7 @@ class RegisterView(PageViewTrackingMixin, MenuContextMixin, SuccessMessageMixin,
|
|||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class ProfileEditView(LoginRequiredMixin, PageViewTrackingMixin, MenuContextMixin, BreadcrumbMixin, UpdateView):
|
class ProfileEditView(LoginRequiredMixin, MenuContextMixin, BreadcrumbMixin, UpdateView):
|
||||||
model = Profile
|
model = Profile
|
||||||
form_class = ProfileForm
|
form_class = ProfileForm
|
||||||
template_name = 'programmer/profile_edit.html'
|
template_name = 'programmer/profile_edit.html'
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user