diff --git a/OneCprogsite/OneCprogsite/__pycache__/settings.cpython-310.pyc b/OneCprogsite/OneCprogsite/__pycache__/settings.cpython-310.pyc index dd9dd5e..d2b1f95 100644 Binary files a/OneCprogsite/OneCprogsite/__pycache__/settings.cpython-310.pyc and b/OneCprogsite/OneCprogsite/__pycache__/settings.cpython-310.pyc differ diff --git a/OneCprogsite/OneCprogsite/settings.py b/OneCprogsite/OneCprogsite/settings.py index fe1cc84..2b2053b 100644 --- a/OneCprogsite/OneCprogsite/settings.py +++ b/OneCprogsite/OneCprogsite/settings.py @@ -50,6 +50,7 @@ MIDDLEWARE = [ 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'programmer.middleware.PageViewMiddleware', ] ROOT_URLCONF = 'OneCprogsite.urls' diff --git a/OneCprogsite/programmer/__pycache__/admin.cpython-310.pyc b/OneCprogsite/programmer/__pycache__/admin.cpython-310.pyc index a9cb1cc..abc1326 100644 Binary files a/OneCprogsite/programmer/__pycache__/admin.cpython-310.pyc and b/OneCprogsite/programmer/__pycache__/admin.cpython-310.pyc differ diff --git a/OneCprogsite/programmer/__pycache__/middleware.cpython-310.pyc b/OneCprogsite/programmer/__pycache__/middleware.cpython-310.pyc new file mode 100644 index 0000000..9fc794e Binary files /dev/null and b/OneCprogsite/programmer/__pycache__/middleware.cpython-310.pyc differ diff --git a/OneCprogsite/programmer/__pycache__/models.cpython-310.pyc b/OneCprogsite/programmer/__pycache__/models.cpython-310.pyc index d55c907..cbbb6fa 100644 Binary files a/OneCprogsite/programmer/__pycache__/models.cpython-310.pyc and b/OneCprogsite/programmer/__pycache__/models.cpython-310.pyc differ diff --git a/OneCprogsite/programmer/__pycache__/urls.cpython-310.pyc b/OneCprogsite/programmer/__pycache__/urls.cpython-310.pyc index 6382875..a20925c 100644 Binary files a/OneCprogsite/programmer/__pycache__/urls.cpython-310.pyc and b/OneCprogsite/programmer/__pycache__/urls.cpython-310.pyc differ diff --git a/OneCprogsite/programmer/__pycache__/views.cpython-310.pyc b/OneCprogsite/programmer/__pycache__/views.cpython-310.pyc index e43f2d6..8ae32e4 100644 Binary files a/OneCprogsite/programmer/__pycache__/views.cpython-310.pyc and b/OneCprogsite/programmer/__pycache__/views.cpython-310.pyc differ diff --git a/OneCprogsite/programmer/admin.py b/OneCprogsite/programmer/admin.py index 3c0e738..bb5f8d1 100644 --- a/OneCprogsite/programmer/admin.py +++ b/OneCprogsite/programmer/admin.py @@ -43,6 +43,17 @@ class CallbackAdmin(admin.ModelAdmin): search_fields = ('name', 'phone', 'email') readonly_fields = ('time_create',) + +@admin.register(PageView) +class PageViewAdmin(admin.ModelAdmin): + list_display = ['url', 'timestamp', 'ip_address'] + list_filter = ['timestamp', 'url'] + search_fields = ['url', 'ip_address'] + date_hierarchy = 'timestamp' + + def get_queryset(self, request): + return super().get_queryset(request).order_by('-timestamp') + admin.site.register(Competence, ProgrammerAdmin) admin.site.register(Recall, RecallAdmin) admin.site.register(Solution, SolutionAdmin) diff --git a/OneCprogsite/programmer/middleware.py b/OneCprogsite/programmer/middleware.py new file mode 100644 index 0000000..494461e --- /dev/null +++ b/OneCprogsite/programmer/middleware.py @@ -0,0 +1,54 @@ +from .models import PageView, Visitor +from django.utils import timezone +from django.db import transaction + + +class PageViewMiddleware: + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request): + # Игнорируем статические файлы и админку + if not request.path.startswith('/static/') and not request.path.startswith('/admin/'): + self.track_page_view(request) + + response = self.get_response(request) + 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 \ No newline at end of file diff --git a/OneCprogsite/programmer/migrations/0011_visitor_pageview.py b/OneCprogsite/programmer/migrations/0011_visitor_pageview.py new file mode 100644 index 0000000..cbe2d9d --- /dev/null +++ b/OneCprogsite/programmer/migrations/0011_visitor_pageview.py @@ -0,0 +1,41 @@ +# Generated by Django 4.2.7 on 2025-11-12 11:43 + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('programmer', '0010_alter_callbackrequest_email_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='Visitor', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('ip_address', models.GenericIPAddressField()), + ('first_visit', models.DateTimeField(default=django.utils.timezone.now)), + ('last_visit', models.DateTimeField(default=django.utils.timezone.now)), + ('visit_count', models.IntegerField(default=1)), + ], + options={ + 'indexes': [models.Index(fields=['ip_address'], name='programmer__ip_addr_2c6dca_idx')], + }, + ), + migrations.CreateModel( + name='PageView', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('url', models.CharField(max_length=500)), + ('timestamp', models.DateTimeField(default=django.utils.timezone.now)), + ('ip_address', models.GenericIPAddressField()), + ('user_agent', models.TextField(blank=True)), + ('referer', models.CharField(blank=True, max_length=500)), + ], + options={ + 'indexes': [models.Index(fields=['url', 'timestamp'], name='programmer__url_9a41b2_idx'), models.Index(fields=['timestamp'], name='programmer__timesta_070072_idx')], + }, + ), + ] diff --git a/OneCprogsite/programmer/migrations/__pycache__/0011_visitor_pageview.cpython-310.pyc b/OneCprogsite/programmer/migrations/__pycache__/0011_visitor_pageview.cpython-310.pyc new file mode 100644 index 0000000..b085443 Binary files /dev/null and b/OneCprogsite/programmer/migrations/__pycache__/0011_visitor_pageview.cpython-310.pyc differ diff --git a/OneCprogsite/programmer/models.py b/OneCprogsite/programmer/models.py index caa1d47..5cd7369 100644 --- a/OneCprogsite/programmer/models.py +++ b/OneCprogsite/programmer/models.py @@ -1,5 +1,6 @@ from django.db import models from django.urls import reverse +from django.utils import timezone class Recall(models.Model): @@ -98,3 +99,29 @@ class CallbackRequest(models.Model): verbose_name = 'Заявка на звонок' verbose_name_plural = 'Заявки на звонок' ordering = ['-time_create'] + + +class PageView(models.Model): + url = models.CharField(max_length=500) + timestamp = models.DateTimeField(default=timezone.now) + ip_address = models.GenericIPAddressField() + user_agent = models.TextField(blank=True) + referer = models.CharField(max_length=500, blank=True) + + class Meta: + indexes = [ + models.Index(fields=['url', 'timestamp']), + models.Index(fields=['timestamp']), + ] + + +class Visitor(models.Model): + ip_address = models.GenericIPAddressField() + first_visit = models.DateTimeField(default=timezone.now) + last_visit = models.DateTimeField(default=timezone.now) + visit_count = models.IntegerField(default=1) + + class Meta: + indexes = [ + models.Index(fields=['ip_address']), + ] diff --git a/OneCprogsite/programmer/templates/admin/base.html b/OneCprogsite/programmer/templates/admin/base.html new file mode 100644 index 0000000..c8f00f5 --- /dev/null +++ b/OneCprogsite/programmer/templates/admin/base.html @@ -0,0 +1,79 @@ + + +
+ + +{{ today_views }}
+{{ weekly_views }}
+{{ unique_visitors }}
+{{ total_views }}
+| Страница | +Просмотров | +
|---|---|
+ {{ page.url }}
+ {% if page.url == '/' %}
+ Главная
+ {% endif %}
+ |
+ {{ page.views }} | +
| Нет данных за выбранный период | +|
| Время | +Страница | +IP-адрес | +
|---|---|---|
| {{ view.timestamp|date:"d.m.Y H:i" }} | +{{ view.url }} |
+ {{ view.ip_address }} | +
| Нет данных | +||