fix: Исправлено образование петель.

mod: современный стиль для вьюх.
This commit is contained in:
2026-02-18 17:38:35 +03:00
parent 65feb36f77
commit 7e33997260
3 changed files with 192 additions and 75 deletions

View File

@@ -29,9 +29,10 @@ sitemaps = {
urlpatterns = [ urlpatterns = [
path('admin/', admin.site.urls), path('admin/', admin.site.urls),
re_path(r'^$', views.index), re_path(r'^$', views.IndexView.as_view()),
re_path(r'^(?P<dq_id>\d{1,12})_\S*$', views.by_id), re_path(r'^(?P<dq_id>\d{1,12})_\S*$', views.DictumDetailView.as_view()),
path('sitemap.xml', sitemap, {'sitemaps': sitemaps}, name='django.contrib.sitemaps.views.sitemap'), path('sitemap.xml', sitemap, {'sitemaps': sitemaps}, name='django.contrib.sitemaps.views.sitemap'),
] ]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

View File

@@ -3,92 +3,189 @@ __author__ = "Sergei Erjemin"
__copyright__ = "Copyright 2020-2026, Sergei Erjemin" __copyright__ = "Copyright 2020-2026, Sergei Erjemin"
__credits__ = ["Sergei Erjemin", ] __credits__ = ["Sergei Erjemin", ]
__license__ = "GPL" __license__ = "GPL"
__version__ = "0.3.9" __version__ = "0.3.0"
__maintainer__ = "Sergei Erjemin" __maintainer__ = "Sergei Erjemin"
__email__ = "erjemin@gmail.com" __email__ = "erjemin@gmail.com"
__status__ = "in progress" __status__ = "in progress"
from django.shortcuts import render
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.views.generic import DetailView, TemplateView
import time import time
import hashlib import hashlib
import random import random
import pytils import pytils
from taggit.models import Tag from web.models import TbDictumAndQuotes, TbImages, TbAuthor
from web.models import TbOrigin, TbDictumAndQuotes, TbImages, TbAuthor
# Create your views here. # Create your views here.
def for_dq(dq):
to_template = {} class CommonContextMixin:
"""
Общий миксин для представлений:
- Логика "одной цитаты" (получение контекста цитаты)
- Общий контекст (куки, тайминги)
"""
def dispatch(self, request, *args, **kwargs):
# Засекаем время в самом начале обработки запроса
self.t_start = time.process_time()
return super().dispatch(request, *args, **kwargs)
def get_filtered_queryset(self):
"""
Возвращает (queryset, tag_slug) на основе GET-параметров запроса.
Если тега нет или он не найден, возвращает (None, None).
"""
tag_slug = self.request.GET.get('tag')
if not tag_slug:
return None, None
dq_qs = TbDictumAndQuotes.objects.all()
# 1. Пробуем найти цитаты, где АВТОР имеет этот тег
author_tag_qs = dq_qs.filter(kAuthor__tags__slug__in=[tag_slug])
if author_tag_qs.exists():
return author_tag_qs, tag_slug
# 2. Если авторов нет, ищем цитаты с этим тегом
quote_tag_qs = dq_qs.filter(tags__slug__in=[tag_slug])
if quote_tag_qs.exists():
return quote_tag_qs, tag_slug
return None, None
def get_dictum_context(self, request, dq, queryset=None):
"""
Получение контекста для цитаты dq. Если queryset передан, используется для логики "следующей цитаты"
и фильтрации по тегу.
"""
context = {}
# Если queryset не передан, используем все объекты
if queryset is None:
queryset = TbDictumAndQuotes.objects.all()
# --- 1. ЛОГИКА ИСТОРИИ СЕССИИ (Предотвращение петель) ---
seen_ids = request.session.get('seen_ids', [])
if dq.id not in seen_ids:
seen_ids.append(dq.id)
if len(seen_ids) > 100:
seen_ids.pop(0)
request.session['seen_ids'] = seen_ids
# --- 2. ГЕНЕРАЦИЯ ЦВЕТОВ ---
num = int(hashlib.blake2s(dq.szContent.encode("utf-8"), digest_size=1).hexdigest(), 16) num = int(hashlib.blake2s(dq.szContent.encode("utf-8"), digest_size=1).hexdigest(), 16)
clr = sorted([num / 2, num / 3, num / 5, num / 7, num / 11, num / 1.5], key=lambda A: random.random()) clr = sorted([num / 2, num / 3, num / 5, num / 7, num / 11, num / 1.5], key=lambda A: random.random())
to_template.update({'CLR': clr}) context.update({'CLR': clr})
to_template.update({'DQ': dq}) context.update({'DQ': dq})
# --- 3. АВТОР И ТЕГИ ---
try: try:
au = TbAuthor.objects.get(id=dq.kAuthor_id) au = TbAuthor.objects.get(id=dq.kAuthor_id)
to_template.update({'AUTHOR': au}) context.update({'AUTHOR': au})
tags = au.tags.names() tags = au.tags.names()
except ObjectDoesNotExist: except ObjectDoesNotExist:
tags = dq.tags.names() tags = dq.tags.names()
tag_and_slug = [] tag_and_slug = []
for i in tags: for i in tags:
tag_and_slug.append({"name": i, "slug": pytils.translit.slugify(i.lower())[:120]}) tag_and_slug.append({"name": i, "slug": pytils.translit.slugify(i.lower())[:120]})
to_template.update({'TAGS': sorted(tag_and_slug, key=lambda x: x["name"])}) # tag_and_slug context.update({'TAGS': sorted(tag_and_slug, key=lambda x: x["name"])})
# --- 4. ВЫБОР КАРТИНКИ ---
if dq.kImages_id is None: if dq.kImages_id is None:
if len(tags) != 0: if len(tags) != 0:
try: tagged_image = TbImages.objects.filter(tags__name__in=tags).order_by('?').first()
# tagged_image = TbImages.objects.filter(tags__name__in=tags).order_by('?').first() if tagged_image:
tagged_image = TbImages.objects.filter(tags__name__in=tags) context.update({'IMAGE': tagged_image.imFile})
random.shuffle(list(tagged_image))
to_template.update({'IMAGE': tagged_image[0].imFile})
except IndexError:
pass
else: else:
to_template.update({'IMAGE': dq.kImages.imFile}) context.update({'IMAGE': dq.kImages.imFile})
# --- 5. СЧЕТЧИК ---
dq.iViewCounter += 1 dq.iViewCounter += 1
dq.save() dq.save(update_fields=['iViewCounter'])
# dq_next = TbDictumAndQuotes.objects.exclude(id=dq.id).order_by('?').first()
dq_next = TbDictumAndQuotes.objects.exclude(id=dq.id)
random.shuffle(list(dq_next))
to_template.update({"NEXT": dq_next[0].id})
to_template.update({"NEXT_TXT": pytils.translit.slugify(dq_next[0].szContent.lower()[:120])})
return to_template
# --- 6. ВЫБОР СЛЕДУЮЩЕЙ ЦИТАТЫ ---
dq_next = queryset.exclude(id__in=seen_ids).order_by('?').first()
def by_id(request, dq_id): if dq_next is None:
t_start = time.process_time() request.session['seen_ids'] = []
template = "index.html" # шаблон dq_next = queryset.exclude(id=dq.id).order_by('?').first()
dq = TbDictumAndQuotes.objects.get(id=dq_id)
to_template = for_dq(dq)
# пероверка, что посетитель согласился со сбором даных через cookies
if request.COOKIES.get('cookie_accept'):
to_template.update({'cookie_accept': 1})
to_template.update({'ticks': float(time.process_time() - t_start)})
response = render(request, template, to_template)
return response
if dq_next:
context.update({"NEXT": dq_next.id})
context.update({"NEXT_TXT": pytils.translit.slugify(dq_next.szContent.lower()[:120])})
def index(request): # Если мы в режиме фильтрации (tag), передаем текущий тег в контекст
t_start = time.process_time()
# проверка на аутентификацию
# if not request.user.is_authenticated():
# return HttpResponseRedirect("/access")
template = "index.html" # шаблон
dq_ = TbDictumAndQuotes.objects
if request.GET.get('tag'): if request.GET.get('tag'):
dq = dq_.filter(kAuthor__tags__slug__in=[request.GET['tag']]).order_by('?').first() context.update({"CURRENT_TAG": request.GET.get('tag')})
if dq is None:
dq = dq_.filter(tags__slug__in=[request.GET['tag']]).order_by('?').first()
if dq is None:
dq = dq_.order_by('?').first()
else:
dq = dq_.first()
to_template = for_dq(dq)
# пероверка, что посетитель согласился со сбором даных через cookies
if request.COOKIES.get('cookie_accept'):
to_template.update({'cookie_accept': 1})
to_template.update({'ticks': float(time.process_time() - t_start)})
response = render(request, template, to_template)
return response
return context
def finalize_context(self, context):
"""
Добавляет общие данные: проверки куки и время выполнения.
"""
if self.request.COOKIES.get('cookie_accept'):
context['cookie_accept'] = 1
# Считаем время от self.t_start, заданного в dispatch
total_time = 0.0
if hasattr(self, 't_start'):
total_time = float(time.process_time() - self.t_start)
context['ticks'] = total_time
return context
class DictumDetailView(CommonContextMixin, DetailView):
model = TbDictumAndQuotes
template_name = "index.html"
pk_url_kwarg = 'dq_id'
context_object_name = 'DQ'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# Определяем контекст фильтрации (если есть тег в URL)
active_qs, _ = self.get_filtered_queryset()
# Используем миксин логики цитаты с учетом фильтра
extras = self.get_dictum_context(self.request, self.object, queryset=active_qs)
context.update(extras)
# Финализируем контекст (куки, тайминги)
return self.finalize_context(context)
class IndexView(CommonContextMixin, TemplateView):
template_name = "index.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
active_qs, _ = self.get_filtered_queryset()
dq = None
if active_qs is not None:
dq = active_qs.order_by('?').first()
if dq is None:
# Если тег не задан, или по тегу ничего не нашлось совсем
# Сбрасываем active_qs на "все", так как специфический контекст пуст
active_qs = TbDictumAndQuotes.objects.all()
# Случайная цитата (с учетом истории, чтобы главная страница тоже не зацикливалась)
seen_ids = self.request.session.get('seen_ids', [])
dq = active_qs.exclude(id__in=seen_ids).order_by('?').first()
if dq is None:
self.request.session['seen_ids'] = []
dq = active_qs.order_by('?').first()
if dq:
# Используем миксин, ОБЯЗАТЕЛЬНО передаем active_qs
extras = self.get_dictum_context(self.request, dq, queryset=active_qs)
context.update(extras)
# Финализируем контекст (куки, тайминги)
return self.finalize_context(context)

View File

@@ -1,7 +1,26 @@
# DicQuo # DicQuo
User-Agent: * User-Agent: *
Allow: / Allow: /
Disallow: Disallow: /admin/
Disallow: /*?tag=
Disallow: /*?
# Optimize for Yandex
Clean-param: tag /
# AI and LLM bots settings
# OpenAI GPT
# User-agent: GPTBot
# Disallow:
# Common Crawl (used by many AI models)
# User-agent: CCBot
# Disallow:
# Google Bard/Gemini
# User-agent: Google-Extended
# Disallow:
Host: dq.cube2.ru Host: dq.cube2.ru
Sitemap: https://dq.cube2.ru/sitemap.xml Sitemap: https://dq.cube2.ru/sitemap.xml