Улучшению приложения main

Улучшению приложения main
29 Май 2026
54 просмотров
Логотип
Планирование 54 просмотра 5 минут чтения
Аудиоверсия статьи Слушать текст в один клик
Скорость:

улучшению приложения main

Анализ кода выявил несколько направлений для улучшения — от критических вопросов безопасности до удобства сопровождения.


🔴 Критические / Безопасность

1. Отсутствует rate-limiting на форме обратной связи (forms.py, views.py)

Проблема: ContactView.post() принимает любое количество запросов без ограничений. Злоумышленник может за секунды завалить почту тысячами сообщений.

Решение: Добавить декоратор django-ratelimit или ручную проверку через кэш:

python

 

# views.py — в ContactView.post()

from django.core.cache import cache

 

def post(self, request, *args, **kwargs):

    ip = request.META.get('REMOTE_ADDR')

    cache_key = f'contact_form_{ip}'

    attempts = cache.get(cache_key, 0)

    if attempts >= 5:  # не более 5 отправок в час

        messages.error(request, 'Слишком много попыток. Попробуйте позже.')

        return redirect(reverse('main:contacts'))

    cache.set(cache_key, attempts + 1, 3600)

    # ... обычная обработка

2. Race condition в счётчике просмотров (views.py#L436)

Проблема: Page.objects.filter(pk=...).update(views=self.object.views + 1) — значение self.object.views берётся из кэша объекта и не является атомарным при параллельных запросах.

Решение:

python

 

from django.db.models import F

Page.objects.filter(pk=self.object.pk).update(views=F('views') + 1)

3. Открытые URL статистики логов (urls.py)

Проблема: /log-stats/ и /error-log/ — публичные URL, хотя в view проверяется is_staff/is_superuser. Лучше защищать на уровне URL или middleware, а не полагаться только на view.

Решение: Перенести эти страницы в поддиректорию /admin/ или добавить login_required на уровне URL.


🟠 Производительность

4. SiteSettings.load() вызывается в каждом view без использования кэша context processor (views.py)

Проблема: ContactView, AboutView, PageDetailView каждый раз вызывают SiteSettings.load() напрямую, игнорируя уже готовый site_settings из context processor.

Решение: В этих view брать данные из context['site_settings'] (он уже установлен context processor site_settings), а не делать новый запрос к БД.

python

 

# Вместо:

site_settings = SiteSettings.load()

 

# Использовать:

site_settings = context.get('site_settings') or SiteSettings.load()

5. N+1 проблема в sidebar_data context processor (context_processors.py#L140-L144)

Проблема: PortfolioItem.objects.all().order_by("-created_at")[:3] — если в шаблоне потом обращаются к item.category или item.images, это вызовет N+1 запросов.

Решение: Добавить select_related / prefetch_related:

python

 

PortfolioItem.objects.select_related('category').order_by('-created_at')[:3]

6. admin_dashboard_stats кэшируется на 60 сек, но выполняет ~15 запросов к БД + системные вызовы

Проблема: При каждом обновлении админки все 15 запросов выполняются сразу. На нагруженном сервере это дорого.

Решение: Вынести сбор статистики в фоновую Celery-задачу, которая запускается по расписанию и кладёт результат в кэш. view только читает кэш.


🟡 Надёжность / Корректность

7. get_previous_page() и get_next_page() работают некорректно при одинаковом order (models.py#L613-L633)

Проблема: Фильтрация Q(order=self.order, created_at__lt=self.created_at) не даёт правильного результата, если обе страницы имеют одинаковый order и одинаковое время создания (такое бывает при импорте данных).

Решение: Добавить pk как финальный тай-брейкер:

python

 

Q(order=self.order, created_at__lt=self.created_at) |

Q(order=self.order, created_at=self.created_at, pk__lt=self.pk)

8. ContactForm не валидирует email/телефон отдельно (forms.py)

Проблема: Поле contact принимает строку без проверки формата — можно ввести абракадабру.

Решение:

python

 

import re

 

def clean_contact(self):

    contact = self.cleaned_data.get('contact', '').strip()

    email_re = r'^[\w.+-]+@[\w-]+\.[a-z]{2,}$'

    phone_re = r'^[\+\d\s\-\(\)]{7,20}$'

    if not re.match(email_re, contact) and not re.match(phone_re, contact):

        raise forms.ValidationError('Введите корректный email или номер телефона.')

    return contact

9. PageDetailView кэширует страницу с @cache_page(60 * 10) — счётчик просмотров обновляется только один раз за 10 минут

Проблема: Кэширование всей страницы и попытка инкрементировать счётчик просмотров несовместимы — при кэшированном ответе get() не вызывается.

Решение: Убрать кэш страницы с PageDetailView или перенести подсчёт просмотров в JavaScript (AJAX-запрос на отдельный endpoint), что даёт более точную статистику и не мешает кэшированию.


🟢 Функциональные улучшения

10. Нет сохранения сообщений из ContactForm в базу данных

Проблема: Сейчас сообщение просто отправляется на email. Если письмо не дошло (сбой SMTP) — данные потеряны навсегда.

Решение: Создать модель ContactMessage и сохранять каждое сообщение в БД перед отправкой email. Это даёт историю обращений прямо в admin-панели.

python

 

# models.py

class ContactMessage(models.Model):

    name = models.CharField('Имя', max_length=100)

    contact = models.CharField('Контакт', max_length=150)

    message = models.TextField('Сообщение')

    ip_address = models.GenericIPAddressField('IP', blank=True, null=True)

    is_read = models.BooleanField('Прочитано', default=False)

    created_at = models.DateTimeField(auto_now_add=True)

    

    class Meta:

        verbose_name = 'Сообщение обратной связи'

        verbose_name_plural = 'Сообщения обратной связи'

        ordering = ['-created_at']

11. SearchView не ищет по отзывам и тикетам

Проблема: Поиск охватывает только News, PortfolioItem и Page. Отзывы и база знаний остаются вне поиска.

Решение: Добавить поиск по reviews.Review и (если есть) knowledge_base.Article по аналогии с существующими блоками.

12. Нет уведомления администратора при создании нового тикета / сообщения в ContactForm

Уже есть send_mail, но нет уведомления в реальном времени. Можно добавить:

  • Django Channels — WebSocket push в admin-панель

  • Telegram Bot — уведомление в Telegram (проще и без зависимостей)

13. Нет автоматической очистки кэша при изменении SiteSettings

Проблема: После изменения настроек сайта (логотип, телефон) кэш живёт до 5 минут — пользователи видят старые данные.

Решение: Добавить сигнал post_save:

python

 

# signals.py

from django.db.models.signals import post_save

from django.core.cache import cache

 

@receiver(post_save, sender=SiteSettings)

def clear_site_settings_cache(sender, **kwargs):

    cache.delete('site_settings')

    cache.delete('menu_pages')

    cache.delete('dynamic_menus_data')

    cache.delete('statistics_banners_user')

    cache.delete('statistics_banners_staff')

    cache.delete('statistics_banners_admin')


🔵 Качество кода

14. Повторяющийся паттерн f"{page_title} - {site_settings.logo_text}" во всех view

Этот паттерн встречается в ContactView, AboutView, LogStatsView, PageDetailView — 4+ раза.

Решение: Вынести в вспомогательный метод BaseView:

python

 

class BaseView(TemplateView):

    def build_page_title(self, title: str, site_settings=None) -> str:

        if site_settings and site_settings.logo_text:

            return f"{title} - {site_settings.logo_text}"

        return title

15. В admin_dashboard_stats context processor выполняется SiteSettings.load() отдельно от основного кэша

Это дублирует запрос. Нужно использовать cache.get('site_settings') как primary источник.

16. Отсутствуют тесты для ContactView.post() и форм

В tests.py нет покрытия для:

  • Успешной отправки формы

  • Невалидных данных формы

  • Rate limiting

  • SearchView с реальными данными


📋 Приоритизация

УлучшениеПриоритетСложность
2F('views') + 1 — атомарный счётчик🔴 Высокий⭐ Очень просто
13Инвалидация кэша через post_save🟠 Средний⭐ Просто
4Устранение лишних SiteSettings.load()🟠 Средний⭐⭐ Просто
1Rate-limiting для ContactForm🔴 Высокий⭐⭐ Просто
8Валидация email/телефона🟠 Средний⭐⭐ Просто
14Рефакторинг build_page_title🟡 Низкий⭐ Очень просто
10Сохранение сообщений в БД🟠 Средний⭐⭐⭐ Средне
9Счётчик просмотров через AJAX🟡 Низкий⭐⭐⭐ Средне
11Расширение поиска🟡 Низкий⭐⭐ Просто
6Celery для dashboard stats🟡 Низкий⭐⭐⭐⭐ Сложно
Как вам статья? Отправьте реакцию!

Обсуждение статьи

0

К этой статье пока нет комментариев. Будьте первым, кто выразит свое мнение!

Оставить комментарий

captcha

Похожие материалы

Наши услуги

Мы делаем для вас лучшее

Комплексный подход к цифровому развитию вашего бизнеса — от создания сайтов до автоматизации и технической поддержки

Создание сайтов

Разрабатываем сайты любой сложности: от лендингов до полноценных маркетплейсов.

  • Лендинги и промо-сайты
  • Интернет-магазины
  • Корпоративные сайты
  • Порталы и каталоги
  • Маркетплейсы

Автоматизация бизнеса

Освобождаем ваше время — автоматизируем рутинные задачи и бизнес-процессы.

  • Автоматизация рутины
  • Документооборот
  • Отчётность и аналитика
  • Email и смс рассылки
  • Уведомления и триггеры

Продвижение сайтов

Приводим целевых посетителей и клиентов через эффективные каналы продвижения.

  • SEO-оптимизация
  • Контекстная реклама
  • SMM и социальные сети
  • Таргетированная реклама
  • Медийная реклама

Техническая поддержка

Обеспечиваем стабильность и безопасность ваших ресурсов в режиме 24/7.

  • Поддержка сайтов
  • Интернет-магазины
  • Обновления и патчи
  • Резервное копирование
  • Мониторинг и безопасность
0+
Завершённых проектов
0+
Лет опыта
0%
Довольных клиентов
0/7
Техническая поддержка