fix: Исправлено образование петель.
mod: современный стиль для вьюх.
This commit is contained in:
@@ -29,9 +29,10 @@ sitemaps = {
|
||||
urlpatterns = [
|
||||
path('admin/', admin.site.urls),
|
||||
|
||||
re_path(r'^$', views.index),
|
||||
re_path(r'^(?P<dq_id>\d{1,12})_\S*$', views.by_id),
|
||||
re_path(r'^$', views.IndexView.as_view()),
|
||||
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'),
|
||||
]
|
||||
|
||||
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||
if settings.DEBUG:
|
||||
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||
|
||||
@@ -3,92 +3,189 @@ __author__ = "Sergei Erjemin"
|
||||
__copyright__ = "Copyright 2020-2026, Sergei Erjemin"
|
||||
__credits__ = ["Sergei Erjemin", ]
|
||||
__license__ = "GPL"
|
||||
__version__ = "0.3.9"
|
||||
__version__ = "0.3.0"
|
||||
__maintainer__ = "Sergei Erjemin"
|
||||
__email__ = "erjemin@gmail.com"
|
||||
__status__ = "in progress"
|
||||
|
||||
from django.shortcuts import render
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.views.generic import DetailView, TemplateView
|
||||
import time
|
||||
import hashlib
|
||||
import random
|
||||
import pytils
|
||||
from taggit.models import Tag
|
||||
from web.models import TbOrigin, TbDictumAndQuotes, TbImages, TbAuthor
|
||||
from web.models import TbDictumAndQuotes, TbImages, TbAuthor
|
||||
|
||||
|
||||
# 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)
|
||||
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})
|
||||
to_template.update({'DQ': dq})
|
||||
context.update({'CLR': clr})
|
||||
context.update({'DQ': dq})
|
||||
|
||||
# --- 3. АВТОР И ТЕГИ ---
|
||||
try:
|
||||
au = TbAuthor.objects.get(id=dq.kAuthor_id)
|
||||
to_template.update({'AUTHOR': au})
|
||||
context.update({'AUTHOR': au})
|
||||
tags = au.tags.names()
|
||||
except ObjectDoesNotExist:
|
||||
tags = dq.tags.names()
|
||||
|
||||
tag_and_slug = []
|
||||
for i in tags:
|
||||
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 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)
|
||||
random.shuffle(list(tagged_image))
|
||||
to_template.update({'IMAGE': tagged_image[0].imFile})
|
||||
except IndexError:
|
||||
pass
|
||||
tagged_image = TbImages.objects.filter(tags__name__in=tags).order_by('?').first()
|
||||
if tagged_image:
|
||||
context.update({'IMAGE': tagged_image.imFile})
|
||||
else:
|
||||
to_template.update({'IMAGE': dq.kImages.imFile})
|
||||
context.update({'IMAGE': dq.kImages.imFile})
|
||||
|
||||
# --- 5. СЧЕТЧИК ---
|
||||
dq.iViewCounter += 1
|
||||
dq.save()
|
||||
# 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
|
||||
dq.save(update_fields=['iViewCounter'])
|
||||
|
||||
# --- 6. ВЫБОР СЛЕДУЮЩЕЙ ЦИТАТЫ ---
|
||||
dq_next = queryset.exclude(id__in=seen_ids).order_by('?').first()
|
||||
|
||||
def by_id(request, dq_id):
|
||||
t_start = time.process_time()
|
||||
template = "index.html" # шаблон
|
||||
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 is None:
|
||||
request.session['seen_ids'] = []
|
||||
dq_next = queryset.exclude(id=dq.id).order_by('?').first()
|
||||
|
||||
if dq_next:
|
||||
context.update({"NEXT": dq_next.id})
|
||||
context.update({"NEXT_TXT": pytils.translit.slugify(dq_next.szContent.lower()[:120])})
|
||||
|
||||
def index(request):
|
||||
t_start = time.process_time()
|
||||
# проверка на аутентификацию
|
||||
# if not request.user.is_authenticated():
|
||||
# return HttpResponseRedirect("/access")
|
||||
template = "index.html" # шаблон
|
||||
dq_ = TbDictumAndQuotes.objects
|
||||
# Если мы в режиме фильтрации (tag), передаем текущий тег в контекст
|
||||
if request.GET.get('tag'):
|
||||
dq = dq_.filter(kAuthor__tags__slug__in=[request.GET['tag']]).order_by('?').first()
|
||||
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
|
||||
context.update({"CURRENT_TAG": request.GET.get('tag')})
|
||||
|
||||
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)
|
||||
|
||||
@@ -1,7 +1,26 @@
|
||||
# DicQuo
|
||||
User-Agent: *
|
||||
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
|
||||
Sitemap: https://dq.cube2.ru/sitemap.xml
|
||||
|
||||
|
||||
Reference in New Issue
Block a user