Оптимизация кода с помощью клауда

This commit is contained in:
NikDizell 2026-03-08 01:19:02 +03:00
parent ad5ac696ca
commit d048510f68
5 changed files with 76 additions and 126 deletions

View File

@ -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):

View File

@ -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)

View File

@ -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>

View File

@ -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

View File

@ -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