Оптимизация кода с помощью клауда
This commit is contained in:
parent
ad5ac696ca
commit
d048510f68
@ -121,33 +121,7 @@ class CallbackAdmin(admin.ModelAdmin):
|
||||
}
|
||||
return render(request, 'admin/callback_stats.html', context)
|
||||
|
||||
class ProgrammerAdmin(admin.ModelAdmin):
|
||||
list_display = ('id', 'title', 'time_create', 'photo', 'is_published')
|
||||
list_display_links = ('id', 'title')
|
||||
search_fields = ('title', 'content')
|
||||
list_editable = ('is_published',)
|
||||
list_filter = ('time_create', 'is_published')
|
||||
|
||||
class RecallAdmin(admin.ModelAdmin):
|
||||
list_display = ('id', 'title', 'time_create', 'scan', 'is_published')
|
||||
list_display_links = ('id', 'title')
|
||||
search_fields = ('title', 'content')
|
||||
list_editable = ('is_published',)
|
||||
list_filter = ('time_create', 'is_published')
|
||||
|
||||
class SolutionAdmin(admin.ModelAdmin):
|
||||
list_display = ('id', 'title', 'time_create', 'is_published')
|
||||
list_display_links = ('id', 'title')
|
||||
search_fields = ('title', 'description', 'implementation')
|
||||
list_editable = ('is_published',)
|
||||
list_filter = ('time_create', 'is_published')
|
||||
|
||||
class HomeAdmin(admin.ModelAdmin):
|
||||
list_display = ('id', 'title', 'time_create', 'is_published')
|
||||
list_display_links = ('id', 'title')
|
||||
search_fields = ('title', 'content')
|
||||
list_editable = ('is_published',)
|
||||
list_filter = ('time_create', 'is_published')
|
||||
|
||||
@admin.register(PageView)
|
||||
class PageViewAdmin(admin.ModelAdmin):
|
||||
|
||||
@ -20,7 +20,7 @@ class Recall(models.Model):
|
||||
return self.title
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('post', kwargs={'post_id': self.pk})
|
||||
return reverse('recall_detail', kwargs={'pk': self.pk})
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'Отзыв'
|
||||
@ -49,7 +49,7 @@ class Competence(models.Model):
|
||||
return self.title
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('post', kwargs={'post_id': self.pk})
|
||||
return reverse('competence_detail', kwargs={'pk': self.pk})
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'Компетенция'
|
||||
@ -70,7 +70,7 @@ class Solution(models.Model):
|
||||
return self.title
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('post', kwargs={'post_id': self.pk})
|
||||
return reverse('solution_detail', kwargs={'pk': self.pk})
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'Проекты'
|
||||
@ -107,7 +107,7 @@ class Home(models.Model):
|
||||
return self.title
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('post', kwargs={'post_id': self.pk})
|
||||
return reverse('home')
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'Главная страница'
|
||||
@ -189,10 +189,10 @@ class Profile(models.Model):
|
||||
|
||||
|
||||
@receiver(post_save, sender=User)
|
||||
def create_or_save_user_profile(sender, instance, **kwargs):
|
||||
def create_or_save_user_profile(sender, instance, created, **kwargs):
|
||||
# Получаем или создаём профиль, затем сохраняем
|
||||
profile, created = Profile.objects.get_or_create(user=instance)
|
||||
profile.save()
|
||||
if created:
|
||||
Profile.objects.get_or_create(user=instance)
|
||||
|
||||
|
||||
@receiver([post_save, post_delete], sender=Home)
|
||||
|
||||
@ -3,11 +3,19 @@
|
||||
{% load static %}
|
||||
{% load seo_tags %}
|
||||
|
||||
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="{% static 'programmer/css/solution-accordion.css' %}">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<article>
|
||||
<h1>{{ solution.title }}</h1>
|
||||
<p>{{ solution.description }}</p>
|
||||
<section>{{ solution.implementation|safe }}</section>
|
||||
<footer>{{ solution.closing|safe }}</footer>
|
||||
</article>
|
||||
|
||||
<div class="page-header">
|
||||
<h1 class="page-title">Проекты автоматизации 1С</h1>
|
||||
<p class="page-subtitle">Реализованные решения и кейсы по автоматизации бизнес-процессов</p>
|
||||
|
||||
@ -14,10 +14,12 @@ urlpatterns = [
|
||||
path('', views.HomePageView.as_view(), name='home'),
|
||||
path('about/', views.AboutPageView.as_view(), name='about'),
|
||||
path('solutions/', views.SolutionListView.as_view(), name='solution'),
|
||||
path('solutions/<int:pk>/', SolutionDetailView.as_view(), name='solution_detail'),
|
||||
# path('competence/', ability, name='ability'),
|
||||
# path('competence/<int:pk>/', CompetenceDetailView.as_view(), name='competence_detail'),
|
||||
path('recall/', views.RecallListView.as_view(), name='recall'),
|
||||
path('recalls/<int:pk>/', RecallDetailView.as_view(), name='recall_detail'),
|
||||
path('blog/', ArticleListView.as_view(), name='blog'),
|
||||
path('post/<int:post_id>/', show_post, name='post'),
|
||||
path('callback/', callback_request, name='callback'),
|
||||
path('admin/statistics/', statistics_view, name='statistics'),
|
||||
# Sitemap
|
||||
|
||||
@ -8,15 +8,13 @@ from django.urls import reverse_lazy
|
||||
from .models import *
|
||||
from django.shortcuts import render, redirect
|
||||
from django.contrib import messages
|
||||
from .models import Home, Solution, Recall, PageView, Visitor, CallbackRequest
|
||||
from .forms import CallbackForm, ProfileForm, UserEditForm, RegistrationForm
|
||||
from django.utils import timezone
|
||||
from datetime import timedelta
|
||||
from .models import PageView, Visitor
|
||||
from django.db.models import Count, QuerySet
|
||||
from django.contrib.auth.decorators import login_required, user_passes_test
|
||||
from django.views.decorators.http import require_GET, require_POST
|
||||
from django.views.generic import TemplateView, ListView, CreateView, UpdateView
|
||||
from django.views.generic import TemplateView, ListView, CreateView, UpdateView, DetailView
|
||||
from .mixins import PageViewTrackingMixin, MenuContextMixin, BreadcrumbMixin
|
||||
from .services import get_published_queryset, track_page_view
|
||||
from typing import Any, Dict, Type
|
||||
@ -271,6 +269,62 @@ class PrivacyPolicyView(TemplateView, MenuContextMixin, BreadcrumbMixin):
|
||||
return [{'title': 'Политика конфиденциальности', 'url_name': None}]
|
||||
|
||||
|
||||
class SolutionDetailView(MenuContextMixin, BreadcrumbMixin, DetailView):
|
||||
model = Solution
|
||||
template_name = 'programmer/solution_detail.html'
|
||||
context_object_name = 'solution'
|
||||
# Отображаются только опубликованные объекты; для неопубликованных выводится ошибка 404
|
||||
queryset = Solution.objects.filter(is_published=True)
|
||||
|
||||
def get_breadcrumbs(self):
|
||||
return [
|
||||
{'title': 'Проекты', 'url_name': 'solution'},
|
||||
{'title': self.object.title, 'url_name': None},
|
||||
]
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['title'] = self.object.get_seo_title()
|
||||
context['meta_description'] = self.object.get_seo_description()
|
||||
return context
|
||||
|
||||
|
||||
class RecallDetailView(MenuContextMixin, BreadcrumbMixin, DetailView):
|
||||
model = Recall
|
||||
template_name = 'programmer/recall_detail.html'
|
||||
context_object_name = 'recall'
|
||||
queryset = Recall.objects.filter(is_published=True)
|
||||
|
||||
def get_breadcrumbs(self):
|
||||
return [
|
||||
{'title': 'Отзывы', 'url_name': 'recall'},
|
||||
{'title': self.object.title, 'url_name': None},
|
||||
]
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['title'] = self.object.get_seo_title()
|
||||
context['meta_description'] = self.object.get_seo_description()
|
||||
return context
|
||||
|
||||
|
||||
class CompetenceDetailView(MenuContextMixin, BreadcrumbMixin, DetailView):
|
||||
model = Competence
|
||||
template_name = 'programmer/competence_detail.html'
|
||||
context_object_name = 'competence'
|
||||
queryset = Competence.objects.filter(is_published=True)
|
||||
|
||||
def get_breadcrumbs(self):
|
||||
return [
|
||||
{'title': 'Компетенции', 'url_name': 'ability'},
|
||||
{'title': self.object.title, 'url_name': None},
|
||||
]
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
return context
|
||||
|
||||
|
||||
@require_POST
|
||||
def callback_request(request: HttpRequest) -> HttpResponse:
|
||||
"""
|
||||
@ -308,13 +362,6 @@ def callback_request(request: HttpRequest) -> HttpResponse:
|
||||
return redirect('home')
|
||||
|
||||
|
||||
def show_post(request: HttpRequest, post_id: int) -> HttpResponse:
|
||||
"""
|
||||
Временная функция для отображения детальной страницы поста.
|
||||
TODO: Реализовать полноценный DetailView для каждой модели.
|
||||
"""
|
||||
return HttpResponse(f"Отображение поста № {post_id}")
|
||||
|
||||
|
||||
def pageNotFound(request: HttpRequest, exception: Exception) -> HttpResponseNotFound:
|
||||
"""Обработчик 404 ошибки."""
|
||||
@ -363,7 +410,7 @@ def statistics_view(request: HttpRequest) -> HttpResponse:
|
||||
'unread_callbacks': CallbackRequest.objects.filter(is_read=False).count(),
|
||||
})
|
||||
|
||||
return render(request, 'admin/statistics.html', stats)
|
||||
return render(request, 'admin/statistics.html', {'stats': stats})
|
||||
|
||||
|
||||
@require_GET
|
||||
@ -371,84 +418,3 @@ def robots_txt(request: HttpRequest) -> HttpResponse:
|
||||
"""Отдает robots.txt."""
|
||||
return render(request, 'robots.txt', content_type='text/plain')
|
||||
|
||||
|
||||
def get_client_ip(request):
|
||||
"""Получаем реальный 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):
|
||||
"""Определяем, нужно ли отслеживать запрос"""
|
||||
|
||||
client_ip = get_client_ip(request)
|
||||
path = request.path
|
||||
|
||||
# Игнорируемые пути (Nextcloud специфичные)
|
||||
nextcloud_paths = [
|
||||
'/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 path.startswith('/static/') or path.startswith('/admin/'):
|
||||
return False
|
||||
|
||||
# Не отслеживаем Nextcloud и Docker запросы
|
||||
if any(path.startswith(p) for p in nextcloud_paths):
|
||||
return False
|
||||
if client_ip in docker_ips:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def track_page_view(request):
|
||||
"""Основная функция отслеживания просмотров"""
|
||||
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],
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"Error tracking page: {e}")
|
||||
|
||||
|
||||
def track_view(view_func):
|
||||
"""Декоратор для отслеживания просмотров страниц"""
|
||||
from functools import wraps
|
||||
|
||||
@wraps(view_func)
|
||||
def _wrapped_view(request, *args, **kwargs):
|
||||
# Отслеживаем просмотр перед выполнением view
|
||||
track_page_view(request)
|
||||
return view_func(request, *args, **kwargs)
|
||||
|
||||
return _wrapped_view
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user