fix: seo и пустое состояние тегов
This commit is contained in:
@@ -56,6 +56,7 @@ INSTALLED_APPS = [
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'django.contrib.sitemaps',
|
||||
# Панель отладки показываем только в dev-окружении при `DEBUG=True`.
|
||||
'debug_toolbar',
|
||||
'django_select2',
|
||||
|
||||
@@ -14,10 +14,12 @@ Including another URLconf
|
||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||
"""
|
||||
from django.contrib import admin
|
||||
from django.contrib.sitemaps.views import sitemap as sitemap_view
|
||||
from django.conf.urls.static import static
|
||||
from django.urls import path, include, re_path
|
||||
from cadpoint import settings
|
||||
from web import views
|
||||
from web.sitemaps import CadpointSitemap
|
||||
|
||||
urlpatterns = [
|
||||
path(
|
||||
@@ -50,7 +52,7 @@ urlpatterns = [
|
||||
# re_path(r'^category-table/(?P<content_id>\d*)-\S*$', views.redirect_item),
|
||||
# re_path(r'^aboutcadpoint.html/(?P<content_id>\d*)-\S*$', views.redirect_item),
|
||||
|
||||
re_path(r'^sitemap.xml$', views.sitemap),
|
||||
path('sitemap.xml', sitemap_view, {'sitemaps': {'cadpoint': CadpointSitemap}}, name='web_sitemap'),
|
||||
|
||||
]
|
||||
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
{% extends "base.jinja2" %}{% load slug_ru %}
|
||||
|
||||
{% block Title %}Все теги{% endblock %}
|
||||
{% block canonical %}https://cadpoint.ru/alltags{% endblock %}
|
||||
{% block page_title %}Все теги | CADpoint{% endblock %}
|
||||
{% block meta_title %}Все теги | CADpoint{% endblock %}
|
||||
{% block og_title %}Все теги | CADpoint{% endblock %}
|
||||
{% block twitter_title %}Все теги | CADpoint{% endblock %}
|
||||
{% block Description %}Все теги сайта CADpoint{% endblock %}
|
||||
{% block meta_description %}Все теги сайта CADpoint{% endblock %}
|
||||
{% block og_description %}Все теги сайта CADpoint{% endblock %}
|
||||
{% block twitter_description %}Все теги сайта CADpoint{% endblock %}
|
||||
{% block Keywords %}cadpoint, теги, alltags, новости{% endblock %}
|
||||
|
||||
{% block CONTENT %}
|
||||
|
||||
@@ -1,36 +1,46 @@
|
||||
<!DOCTYPE html>{% load static %}<html lang="ru">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="content-language" content="ru" />
|
||||
<meta http-equiv="Date" content="{% block Date4Meta %}{% now 'c' %}{% endblock %}" />
|
||||
<meta http-equiv="Last-Modified" content="{% block Last4Meta %}{% now 'c' %}{% endblock %}" />
|
||||
<meta http-equiv="Expires" content="{% block Expires4Meta %}{% now 'c' %}{% endblock %}" />
|
||||
<meta http-equiv="Cache-Control" content="no-cache">
|
||||
<meta name="generator" content="Microsoft FrontPage 1.0" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=0.5" />
|
||||
<meta name="description" content="{% block Description %}{% endblock %}" />
|
||||
<meta name="keywords" content="{% block Keywords %}{% endblock %}" />
|
||||
<meta name="description" content="{% block Description %}CADpoint — новости о 3D-печати и САПР{% endblock %}" />
|
||||
<meta name="keywords" content="{% block Keywords %}cadpoint, 3D-печать, САПР, новости{% endblock %}" />
|
||||
<meta name="copyright" lang="ru" content="Sergei Erjemin{% block CopyrightAuthor4Meta %}{% endblock %}." />
|
||||
<meta name="robots" content="index,follow" />
|
||||
<meta name="document-state" content="{{ META_DOCUMENT_STATE|default:'Dynamic' }}" />
|
||||
<meta name="generator" content="CADPOINT.RU 0.1β by Python/Django" />
|
||||
<meta name="format-detection" content="telephone=no" />
|
||||
<meta name="twitter:dnt" content="on" />
|
||||
<title>CADPOINT.RU - {% block Title %}{% endblock %}</title>
|
||||
<link rel="canonical" href="{% block canonical %}https://cadpoint.ru{% endblock %}" />{% comment %}
|
||||
<!-- Favicons -->{% endcomment %}
|
||||
<meta name="theme-color" content="#F5F5F5" />{% comment %}theme-color предоставляет браузерам цвет CSS для
|
||||
настройки отображения страницы или окружающего пользовательского интерфейса.{% endcomment %}
|
||||
<title>{% block page_title %}CADPOINT.RU{% endblock %}</title>
|
||||
<meta name="meta-title" content="{% block meta_title %}CADPOINT.RU{% endblock %}" />
|
||||
<meta name="meta-description" content="{% block meta_description %}CADpoint — новости о 3D-печати и САПР{% endblock %}" />
|
||||
<link rel="canonical" href="{% block canonical %}{{ request.scheme }}://{{ request.get_host }}{{ request.path }}{% endblock %}" />
|
||||
<meta property="og:site_name" content="CADPOINT.RU" />
|
||||
<meta property="og:locale" content="ru_RU" />
|
||||
<meta property="og:title" content="{% block og_title %}CADPOINT.RU{% endblock %}" />
|
||||
<meta property="og:description" content="{% block og_description %}CADpoint — новости о 3D-печати и САПР{% endblock %}" />
|
||||
<meta property="og:url" content="{% block og_url %}{{ request.scheme }}://{{ request.get_host }}{{ request.path }}{% endblock %}" />
|
||||
<meta property="og:type" content="{% block og_type %}website{% endblock %}" />
|
||||
<meta property="og:image" content="{% block og_image %}{% static 'img/og-cadpoint-default.png' %}{% endblock %}" />
|
||||
<meta property="og:image:alt" content="{% block og_image_alt %}CADPOINT.RU{% endblock %}" />
|
||||
<meta name="twitter:card" content="{% block twitter_card %}summary_large_image{% endblock %}" />
|
||||
<meta name="twitter:title" content="{% block twitter_title %}CADPOINT.RU{% endblock %}" />
|
||||
<meta name="twitter:description" content="{% block twitter_description %}CADpoint — новости о 3D-печати и САПР{% endblock %}" />
|
||||
<meta name="twitter:image" content="{% block twitter_image %}{% static 'img/og-cadpoint-default.png' %}{% endblock %}" />
|
||||
<meta name="theme-color" content="#F5F5F5" />
|
||||
{# Шутка #}<meta name="generator" content="Microsoft FrontPage 1.0"/>
|
||||
<link rel="icon" type="image/svg+xml" href="{% static 'svgs/favicon.svg' %}" />
|
||||
<link rel="icon" type="image/png" href="{% static 'img/favicon.png' %}" />
|
||||
<link rel="shortcut icon" type="image/x-icon" href="{% static 'img/favicon.ico' %}" />
|
||||
<link rel="apple-touch-icon" href="{% static 'img/favicon.png' %}" />{% comment %}
|
||||
<!-- css -->{% endcomment %}
|
||||
<link rel="apple-touch-icon" href="{% static 'img/favicon.png' %}" />
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous" />
|
||||
<link rel="stylesheet" href="{% static 'css/cadpoint.css' %}" />
|
||||
<link rel="stylesheet" href="{% static 'css/cadpoint.css' %}" />{% block ExtraHead %}
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebSite",
|
||||
"name": "CADPOINT.RU",
|
||||
"url": "{{ request.scheme }}://{{ request.get_host }}/"
|
||||
}
|
||||
</script>{% endblock %}
|
||||
</head>
|
||||
<body>{% block META_OG %}{% endblock %}{% block BODY %}
|
||||
<body>{% block BODY %}
|
||||
{% block Top_CSS1 %}{% endblock %}{% block Top_CSS2 %}{% endblock %}{% block Top_CSS3 %}{% endblock %}{% include "blocks/header_nav.jinja2" %}{% block CONTENT %}{% endblock %}
|
||||
{% include "blocks/footer.jinja2" %}{% if COOKIES %}
|
||||
{% include "blocks/accept-cookies.jinja2" %}{% endif %}
|
||||
|
||||
@@ -1,51 +1,23 @@
|
||||
{% extends "base.jinja2" %}{% load static %}{% load thumbnail %}{% load slug_ru %}
|
||||
|
||||
{% block META_OG %}{% comment %} РАЗМЕТКА Open Graph ДЛЯ СОЦ-СЕТЕЙ
|
||||
подробности: https://habr.com/ru/company/macloud/blog/555082/{% endcomment %}
|
||||
<meta property="og:title" content="CADPOINT.RU / {% if TAGS_L %}тег: {% for I in TAGS_IN_PAGE %}{% if I.slug in TAGS_L %}{{ I.name|upper }} / {% endif %}{% endfor %}{% endif %}{% if PAGE_OF_LIST %}СТРАНИЦА {{ PAGE_OF_LIST|add:'1' }}{% else %}ГЛАВНАЯ{% endif %}">{% comment %} Уникальное название страницы.
|
||||
Используется парсерами URL-адресов в социальных сетях, таких как Twitter или Facebook{% endcomment %}
|
||||
<meta property="og:description" content="CADpoint / {% if TAGS_L %}тег: {% for I in TAGS_IN_PAGE %}{% if I.slug in TAGS_L %}{{ I.name }} / {% endif %}{% endfor %}{% endif %}{% if PAGE_OF_LIST %}Страница {{ PAGE_OF_LIST|add:'1' }}{% else %}Главная{% endif %}" />{% comment %} Уникальное описание страницы.
|
||||
Используется парсерами URL-адресов в социальных сетях, таких как Twitter или Facebook.{% endcomment %}
|
||||
<meta property="og:image" content="{% static 'img/og-cadpoint-default.png' %}" />{% comment %} Изображение, отображаемое, когда вы
|
||||
делитесь ссылкой на страницу в социальных сетях, приложениях чата или других сайтах,
|
||||
которые очищают URL-адреса.
|
||||
В идеале это должно быть квадратное изображение с важным содержанием, размещенным
|
||||
в центре квадрата в прямоугольнике с соотношением сторон 2:1. Это гарантирует,
|
||||
что изображение будет хорошо смотреться на карточках с изображениями прямоугольной
|
||||
и квадратной формы.{% endcomment %}
|
||||
<meta property="og:image:alt" content="cadpint.ru: новости 3D-печати и Систем Автоматичекого Проектирования" />{% comment %}
|
||||
Описание изображения.
|
||||
Не используйте этот метатег, если изображение носит чисто декоративный характер
|
||||
и не содержит значимой информации. Программы чтения с экрана игнорируют
|
||||
изображение, если мы предоставлен замещающий текст.{% endcomment %}
|
||||
<meta property="og:locale" content="ru_RU" />{% comment %} Естественный язык страницы.{% endcomment %}
|
||||
<meta property="og:type" content="website" />{% comment %} Тип контента, которым вы делитесь,
|
||||
например website, article, или video.movie{% endcomment %}
|
||||
<meta property="og:url" content="https://cadpoint.ru{% if TAGS_L %}{{ TAGS_S }}{% endif %}{% if PAGE_OF_LIST %}/p{{ PAGE_OF_LIST }}{% endif %}" />{% comment %} Канонический URL страницы.
|
||||
Обязательное свойство для допустимых страниц Open Graph.{% endcomment %}
|
||||
<meta name="twitter:card" content="summary_large_image" />{% comment %} определяет, как будут выглядеть
|
||||
карточки при публикации в Twitter. Есть два варианта для веб-сайтов: summary
|
||||
и summary_large_image{% endcomment %}
|
||||
<meta property="article:modified_time" content="{{ LENTA.0.dtContentTimeStamp|date:'c' }}" />
|
||||
<meta property="article:published_time" content="{{ LENTA.0.tdContentPublishUp|date:'c' }}" />{% endblock %}
|
||||
|
||||
<!--- ТИТУЛ --->
|
||||
{% block Title %}{% if TAGS_L %}Тема: {% for I in TAGS_IN_PAGE %}{% if I.slug in TAGS_L %}{{ I.name }} - {% endif %}{% endfor %}{% endif %}{% if PAGE_OF_LIST %}Страница {{ PAGE_OF_LIST|add:'1' }}{% else %}Главная{% endif %}{% endblock %}
|
||||
{% block canonical %}https://cadpoint.ru{% if TAGS_L %}{{ TAGS_S }}{% endif %}{% if PAGE_OF_LIST %}/p{{ PAGE_OF_LIST }}{% endif %}{% endblock %}
|
||||
{% block Description %}CADpoint / {% if TAGS_L %}тег: {% for I in TAGS_IN_PAGE %}{% if I.slug in TAGS_L %}{{ I.name }} / {% endif %}{% endfor %}{% endif %}{% if PAGE_OF_LIST %}Страница {{ PAGE_OF_LIST|add:'1' }}{% else %}Главная{% endif %}{% endblock %}
|
||||
{% block Keywords %}cadpoint, {% for I in TAGS_IN_PAGE %}{{ I.name }}, {% endfor %}новости{% if PAGE_OF_LIST %} , стр. {{ PAGE_OF_LIST|add:'1' }}{% endif %}{% endblock %}
|
||||
{% block Date4Meta %}{{ LENTA.0.tdContentPublishUp|date:'c' }}{% endblock %}"
|
||||
{% block Last4Meta %}{{ LENTA.0.dtContentTimeStamp|date:'c' }}{% endblock %}"
|
||||
{% block Expires4Meta %}{% now 'c' %}{% endblock %}"
|
||||
|
||||
{% block page_title %}{% if EMPTY_STATE_TITLE %}{{ EMPTY_STATE_TITLE }}{% elif SELECTED_TAGS %}Тема: {% for I in SELECTED_TAGS %}{{ I.name }} - {% endfor %}{% elif TAGS_L %}Тема: {% for I in TAGS_IN_PAGE %}{% if I.slug in TAGS_L %}{{ I.name }} - {% endif %}{% endfor %}{% endif %}{% if PAGE_OF_LIST and not EMPTY_STATE_TITLE %}Страница {{ PAGE_OF_LIST|add:'1' }}{% elif not SELECTED_TAGS and not EMPTY_STATE_TITLE %}Главная{% endif %} | CADpoint{% endblock %}
|
||||
{% block meta_title %}{% if EMPTY_STATE_TITLE %}{{ EMPTY_STATE_TITLE }}{% elif SELECTED_TAGS %}Тема: {% for I in SELECTED_TAGS %}{{ I.name }} - {% endfor %}{% elif TAGS_L %}Тема: {% for I in TAGS_IN_PAGE %}{% if I.slug in TAGS_L %}{{ I.name }} - {% endif %}{% endfor %}{% endif %}{% if PAGE_OF_LIST and not EMPTY_STATE_TITLE %}Страница {{ PAGE_OF_LIST|add:'1' }}{% elif not SELECTED_TAGS and not EMPTY_STATE_TITLE %}Главная{% endif %} | CADpoint{% endblock %}
|
||||
{% block og_title %}{% if EMPTY_STATE_TITLE %}{{ EMPTY_STATE_TITLE }}{% elif SELECTED_TAGS %}Тема: {% for I in SELECTED_TAGS %}{{ I.name }} - {% endfor %}{% elif TAGS_L %}Тема: {% for I in TAGS_IN_PAGE %}{% if I.slug in TAGS_L %}{{ I.name }} - {% endif %}{% endfor %}{% endif %}{% if PAGE_OF_LIST and not EMPTY_STATE_TITLE %}Страница {{ PAGE_OF_LIST|add:'1' }}{% elif not SELECTED_TAGS and not EMPTY_STATE_TITLE %}Главная{% endif %} | CADpoint{% endblock %}
|
||||
{% block twitter_title %}{% if EMPTY_STATE_TITLE %}{{ EMPTY_STATE_TITLE }}{% elif SELECTED_TAGS %}Тема: {% for I in SELECTED_TAGS %}{{ I.name }} - {% endfor %}{% elif TAGS_L %}Тема: {% for I in TAGS_IN_PAGE %}{% if I.slug in TAGS_L %}{{ I.name }} - {% endif %}{% endfor %}{% endif %}{% if PAGE_OF_LIST and not EMPTY_STATE_TITLE %}Страница {{ PAGE_OF_LIST|add:'1' }}{% elif not SELECTED_TAGS and not EMPTY_STATE_TITLE %}Главная{% endif %} | CADpoint{% endblock %}
|
||||
{% block Description %}{% if EMPTY_STATE_MESSAGE %}{{ EMPTY_STATE_MESSAGE }}{% else %}CADpoint / {% if SELECTED_TAGS %}тег: {% for I in SELECTED_TAGS %}{{ I.name }} / {% endfor %}{% elif TAGS_L %}тег: {% for I in TAGS_IN_PAGE %}{% if I.slug in TAGS_L %}{{ I.name }} / {% endif %}{% endfor %}{% endif %}{% if PAGE_OF_LIST and not SELECTED_TAGS %}Страница {{ PAGE_OF_LIST|add:'1' }}{% elif not SELECTED_TAGS %}Главная{% endif %}{% endif %}{% endblock %}
|
||||
{% block meta_description %}{% if EMPTY_STATE_MESSAGE %}{{ EMPTY_STATE_MESSAGE }}{% else %}CADpoint / {% if SELECTED_TAGS %}тег: {% for I in SELECTED_TAGS %}{{ I.name }} / {% endfor %}{% elif TAGS_L %}тег: {% for I in TAGS_IN_PAGE %}{% if I.slug in TAGS_L %}{{ I.name }} / {% endif %}{% endfor %}{% endif %}{% if PAGE_OF_LIST and not SELECTED_TAGS %}Страница {{ PAGE_OF_LIST|add:'1' }}{% elif not SELECTED_TAGS %}Главная{% endif %}{% endif %}{% endblock %}
|
||||
{% block og_description %}{% if EMPTY_STATE_MESSAGE %}{{ EMPTY_STATE_MESSAGE }}{% else %}CADpoint / {% if SELECTED_TAGS %}тег: {% for I in SELECTED_TAGS %}{{ I.name }} / {% endfor %}{% elif TAGS_L %}тег: {% for I in TAGS_IN_PAGE %}{% if I.slug in TAGS_L %}{{ I.name }} / {% endif %}{% endfor %}{% endif %}{% if PAGE_OF_LIST and not SELECTED_TAGS %}Страница {{ PAGE_OF_LIST|add:'1' }}{% elif not SELECTED_TAGS %}Главная{% endif %}{% endif %}{% endblock %}
|
||||
{% block twitter_description %}{% if EMPTY_STATE_MESSAGE %}{{ EMPTY_STATE_MESSAGE }}{% else %}CADpoint / {% if SELECTED_TAGS %}тег: {% for I in SELECTED_TAGS %}{{ I.name }} / {% endfor %}{% elif TAGS_L %}тег: {% for I in TAGS_IN_PAGE %}{% if I.slug in TAGS_L %}{{ I.name }} / {% endif %}{% endfor %}{% endif %}{% if PAGE_OF_LIST and not SELECTED_TAGS %}Страница {{ PAGE_OF_LIST|add:'1' }}{% elif not SELECTED_TAGS %}Главная{% endif %}{% endif %}{% endblock %}
|
||||
{% block Keywords %}cadpoint, {% if SELECTED_TAGS %}{% for I in SELECTED_TAGS %}{{ I.name }}, {% endfor %}{% else %}{% for I in TAGS_IN_PAGE %}{{ I.name }}, {% endfor %}{% endif %}новости{% if PAGE_OF_LIST %} , стр. {{ PAGE_OF_LIST|add:'1' }}{% endif %}{% endblock %}
|
||||
|
||||
{% block CONTENT %}{# <!-- ХЛЕБНЫЕ КРОШКИ: НАЧАЛО -->#}
|
||||
<div class="container bread-crumb">
|
||||
<div class="row">
|
||||
<nav class="col-12 х" aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item nw s"><a href="/"><i class="bi bi-house-door" title="Главная"></i> Главная</a></li>{% for t in TAGS_IN_PAGE %}{% if t.slug in TAGS_L %}
|
||||
<li class="breadcrumb-item nw s"><a href="{{ TAGS_S|rm_tag:t.slug }}"><i class="bi bi-tag" title="тэг"></i> {{ t.name }}</a></li>{% endif %}{% endfor %}{% if PAGE_OF_LIST %}
|
||||
<li class="breadcrumb-item nw s"><a href="/"><i class="bi bi-house-door" title="Главная"></i> Главная</a></li>{% if SELECTED_TAGS %}{% for t in SELECTED_TAGS %}
|
||||
<li class="breadcrumb-item nw s"><a href="{{ TAGS_S|rm_tag:t.slug }}"><i class="bi bi-tag" title="тэг"></i> {{ t.name }}</a></li>{% endfor %}{% else %}{% for t in TAGS_IN_PAGE %}{% if t.slug in TAGS_L %}
|
||||
<li class="breadcrumb-item nw s"><a href="{{ TAGS_S|rm_tag:t.slug }}"><i class="bi bi-tag" title="тэг"></i> {{ t.name }}</a></li>{% endif %}{% endfor %}{% endif %}{% if PAGE_OF_LIST %}
|
||||
<li class="breadcrumb-item active nw s" aria-current="page">Страница {{ PAGE_OF_LIST|add:'1' }}</li>{% endif %}
|
||||
</ol>
|
||||
</nav>
|
||||
@@ -100,6 +72,21 @@
|
||||
</ul>
|
||||
</nav>
|
||||
</div>{# НАВИГАЦИЯ ПО СТРАНИЦАМ СО СПИСКАМИ КОНТЕНТА ИЗ ПРОИЗВОЛЬНОЙ КАТЕГОРИИ: КОНЕЦ #}{% endif %}
|
||||
{% if not LENTA %}
|
||||
<div class="row default-list">
|
||||
<div class="col-12">
|
||||
<div class="alert alert-warning mb-0" role="alert">
|
||||
<h3 class="h5 mb-2">{% if EMPTY_STATE_TITLE %}{{ EMPTY_STATE_TITLE }}{% else %}Новостей не найдено{% endif %}</h3>
|
||||
<p class="mb-0">{% if EMPTY_STATE_MESSAGE %}{{ EMPTY_STATE_MESSAGE }}{% else %}По выбранному разделу пока нет новостей.{% endif %}</p>
|
||||
<p class="mb-0 mt-3">
|
||||
<a href="/">На главную</a>
|
||||
<span class="mx-2">·</span>
|
||||
<a href="/alltags">Все теги</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>{#<!-- POINT-СРАНИЦА: КОНЕЦ -->#}{% endblock %}
|
||||
|
||||
@@ -1,46 +1,71 @@
|
||||
{% extends "base.jinja2" %}{% load static %}{% load thumbnail %}{% load slug_ru %}
|
||||
|
||||
{% block META_OG %}{% comment %} РАЗМЕТКА Open Graph ДЛЯ СОЦ-СЕТЕЙ
|
||||
подробности: https://habr.com/ru/company/macloud/blog/555082/ и https://ogp.me/{% endcomment %}
|
||||
<meta property="og:title" content="cadpoint.ru: {{ ITEM.szContentHead|safe_html_ss }}">{% comment %} Уникальное название страницы.
|
||||
Используется парсерами URL-адресов в социальных сетях, таких как Twitter или Facebook{% endcomment %}
|
||||
<meta property="og:description" content="CADpoint: {% if ITEM.szContentDescription %}{{ ITEM.szContentDescription }}{% else %}{{ ITEM.szContentHead|safe_html_ss }}{% endif %}" />{% comment %} Уникальное описание страницы.
|
||||
Используется парсерами URL-адресов в социальных сетях, таких как Twitter или Facebook.{% endcomment %}
|
||||
<meta property="og:image" content="{% if ITEM.imgContentPreview is None %}{% static 'img/og-cadpoint-default.png' %}{% else %}{% thumbnail ITEM.imgContentPreview 680x680 upscale %}{% endif %}" />{% comment %} Изображение, отображаемое, когда вы
|
||||
делитесь ссылкой на страницу в социальных сетях, приложениях чата или других сайтах,
|
||||
которые очищают URL-адреса.
|
||||
В идеале это должно быть квадратное изображение с важным содержанием, размещенным
|
||||
в центре квадрата в прямоугольнике с соотношением сторон 2:1. Это гарантирует,
|
||||
что изображение будет хорошо смотреться на карточках с изображениями прямоугольной
|
||||
и квадратной формы.{% endcomment %}
|
||||
<meta property="og:image:alt" content="cadpoint.ru: {{ ITEM.szContentHead|safe_html_ss }}" />{% comment %}
|
||||
Описание изображения.
|
||||
Не используйте этот метатег, если изображение носит чисто декоративный характер
|
||||
и не содержит значимой информации. Программы чтения с экрана игнорируют
|
||||
изображение, если мы предоставлен замещающий текст.{% endcomment %}
|
||||
<meta property="og:locale" content="ru_RU" />{% comment %} Естественный язык страницы.{% endcomment %}
|
||||
<meta property="og:type" content="website" />{% comment %} Тип контента, которым вы делитесь,
|
||||
например website, article, или video.movie{% endcomment %}
|
||||
<meta property="og:url" content="https://cadpoint.ru/item/{{ ITEM.id }}-{{ ITEM.szContentSlug }}" />{% comment %} Канонический URL страницы.
|
||||
Обязательное свойство для допустимых страниц Open Graph.{% endcomment %}
|
||||
<meta name="twitter:card" content="summary_large_image" />{% comment %} определяет, как будут выглядеть
|
||||
карточки при публикации в Twitter. Есть два варианта для веб-сайтов: summary
|
||||
и summary_large_image{% endcomment %}{% for t in ITEM.tags.all%}
|
||||
<meta property="article:tag" content="{{ t.name|lower }}">{% comment %} определяет тематику статьи, ключевые слова или хэштеги. Если тематик несколько, перечислите их в разных метатегах.{% endcomment %}{% endfor %}
|
||||
<meta property="article:modified_time" content="{{ ITEM.dtContentTimeStamp|date:'c' }}">
|
||||
<meta property="article:published_time" content="{{ ITEM.tdContentPublishUp|date:'c' }}">
|
||||
{% block page_title %}{{ ITEM.szContentHead|safe_html_ss }} | CADpoint{% endblock %}
|
||||
|
||||
{% block canonical %}{{ request.scheme }}://{{ request.get_host }}/item/{{ ITEM.id }}-{{ ITEM.szContentSlug }}{% endblock %}
|
||||
{% block og_url %}{{ request.scheme }}://{{ request.get_host }}/item/{{ ITEM.id }}-{{ ITEM.szContentSlug }}{% endblock %}
|
||||
|
||||
{% block Description %}{% if ITEM.szContentDescription %}{{ ITEM.szContentDescription }}{% else %}{{ ITEM.szContentHead|safe_html_ss }}{% endif %}{% endblock %}
|
||||
|
||||
{% block meta_title %}{{ ITEM.szContentHead|safe_html_ss }} | CADpoint{% endblock %}
|
||||
|
||||
{% block og_title %}{{ ITEM.szContentHead|safe_html_ss }} | CADpoint{% endblock %}
|
||||
|
||||
{% block twitter_title %}{{ ITEM.szContentHead|safe_html_ss }} | CADpoint{% endblock %}
|
||||
|
||||
{% block meta_description %}{% if ITEM.szContentDescription %}{{ ITEM.szContentDescription }}{% else %}{{ ITEM.szContentHead|safe_html_ss }}{% endif %}{% endblock %}
|
||||
|
||||
{% block og_description %}{% if ITEM.szContentDescription %}{{ ITEM.szContentDescription }}{% else %}{{ ITEM.szContentHead|safe_html_ss }}{% endif %}{% endblock %}
|
||||
|
||||
{% block twitter_description %}{% if ITEM.szContentDescription %}{{ ITEM.szContentDescription }}{% else %}{{ ITEM.szContentHead|safe_html_ss }}{% endif %}{% endblock %}
|
||||
|
||||
{% block Keywords %}cadpoint{% if ITEM.szContentKeywords %}, {{ ITEM.szContentKeywords }}{% endif %}{% with item_tags=ITEM.tags.all %}{% if item_tags %}, {% for t in item_tags %}{{ t.name }}{% if not forloop.last %}, {% endif %}{% endfor %}{% endif %}{% endwith %}, новости{% endblock %}
|
||||
|
||||
{% block og_type %}article{% endblock %}
|
||||
|
||||
{% block og_image %}{% if ITEM.imgContentPreview is None %}{% static 'img/og-cadpoint-default.png' %}{% else %}{% thumbnail ITEM.imgContentPreview 680x680 upscale %}{% endif %}{% endblock %}
|
||||
|
||||
{% block og_image_alt %}{{ ITEM.szContentHead|safe_html_ss }} | CADpoint{% endblock %}
|
||||
|
||||
{% block twitter_card %}summary_large_image{% endblock %}
|
||||
|
||||
{% block twitter_image %}{% if ITEM.imgContentPreview is None %}{% static 'img/og-cadpoint-default.png' %}{% else %}{% thumbnail ITEM.imgContentPreview 680x680 upscale %}{% endif %}{% endblock %}
|
||||
|
||||
{% block ExtraHead %}{{ block.super }}{% for t in ITEM.tags.all %}
|
||||
<meta property="article:tag" content="{{ t.name|lower }}" />{% endfor %}
|
||||
<meta property="article:published_time" content="{{ ITEM.tdContentPublishUp|date:'Y-m-d' }}T{{ ITEM.tdContentPublishUp|date:'H:i' }}{{ ITEM.tdContentPublishUp|date:'O'|slice:':3' }}:{{ ITEM.tdContentPublishUp|date:'O'|slice:'3:' }}" />
|
||||
<meta property="article:modified_time" content="{{ ITEM.dtContentTimeStamp|date:'Y-m-d' }}T{{ ITEM.dtContentTimeStamp|date:'H:i' }}{{ ITEM.dtContentTimeStamp|date:'O'|slice:':3' }}:{{ ITEM.dtContentTimeStamp|date:'O'|slice:'3:' }}" />
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Article",
|
||||
"mainEntityOfPage": {
|
||||
"@type": "WebPage",
|
||||
"@id": "{{ request.scheme }}://{{ request.get_host }}/item/{{ ITEM.id }}-{{ ITEM.szContentSlug }}"
|
||||
},
|
||||
"headline": "{{ ITEM.szContentHead|safe_html_ss|escapejs }}",
|
||||
"description": "{% if ITEM.szContentDescription %}{{ ITEM.szContentDescription|escapejs }}{% else %}{{ ITEM.szContentHead|safe_html_ss|escapejs }}{% endif %}",
|
||||
"image": [
|
||||
"{% if ITEM.imgContentPreview is None %}{% static 'img/og-cadpoint-default.png' %}{% else %}{% thumbnail ITEM.imgContentPreview 680x680 upscale %}{% endif %}"
|
||||
],
|
||||
"datePublished": "{{ ITEM.tdContentPublishUp|date:'Y-m-d' }}T{{ ITEM.tdContentPublishUp|date:'H:i' }}{{ ITEM.tdContentPublishUp|date:'O'|slice:':3' }}:{{ ITEM.tdContentPublishUp|date:'O'|slice:'3:' }}",
|
||||
"dateModified": "{{ ITEM.dtContentTimeStamp|date:'Y-m-d' }}T{{ ITEM.dtContentTimeStamp|date:'H:i' }}{{ ITEM.dtContentTimeStamp|date:'O'|slice:':3' }}:{{ ITEM.dtContentTimeStamp|date:'O'|slice:'3:' }}",
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "Sergei Erjemin"
|
||||
},
|
||||
"publisher": {
|
||||
"@type": "Organization",
|
||||
"name": "CADPOINT.RU",
|
||||
"logo": {
|
||||
"@type": "ImageObject",
|
||||
"url": "{{ request.scheme }}://{{ request.get_host }}{% static 'svgs/favicon.svg' %}"
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
<!--- ТИТУЛ --->
|
||||
{% block Title %}{{ ITEM.szContentHead|safe_html_ss }}{% endblock %}
|
||||
{% block canonical %}https://cadpoint.ru/item/{{ ITEM.id }}-{{ ITEM.szContentSlug }}{% endblock %}
|
||||
{% block Description %}CADpoint: {% if ITEM.szContentDescription %}{{ ITEM.szContentDescription }}{% else %}{{ ITEM.szContentHead|safe_html_ss }}{% endif %}{% endblock %}
|
||||
{% block Keywords %}cadpoint, {% for t in ITEM.tags.all %}{{ t.name }}, {% endfor %}{{ ITEM.szContentKeywords }}, новости{% endblock %}
|
||||
{% block Date4Meta %}{{ ITEM.tdContentPublishUp|date:'c' }}{% endblock %}"
|
||||
{% block Last4Meta %}{{ ITEM.dtContentTimeStamp|date:'c' }}{% endblock %}"
|
||||
{% block Expires4Meta %}{% now 'c' %}{% endblock %}"
|
||||
|
||||
|
||||
{% block CONTENT %}{# <!-- ХЛЕБНЫЕ КРОШКИ: НАЧАЛО -->#}<div class="container bread-crumb">
|
||||
<div class="row">
|
||||
<nav class="col-12 х" aria-label="breadcrumb">
|
||||
@@ -76,7 +101,7 @@
|
||||
</div>{% endif %}{% endfor %}
|
||||
</nav>{#<!-- боковая навигация: конец-->#}
|
||||
</div>
|
||||
{# <!-- НИЖНЯЯ НАВИГАЦИЯ-ПАДЖИНАТОР ПО НОВОСТЯМ: НАЧАЛО--> #}{% if PER_PAGE %}
|
||||
{# <!-- НИЖНЯЯ НАВИГАЦИЯ-ПАДЖИНАТОР ПО НОВОСТЯМ: НАЧАЛО--> #}{% if PER_PAGE %}
|
||||
<nav class="row" aria-label="Навигация по контенту">
|
||||
<ul class="col offset-md-3 pagination px-1">{% if ITEMS_BEFORE.0.id %}
|
||||
<li class="page-item"><a class="page-link" href="/item/{{ ITEMS_BEFORE.0.id }}-{{ ITEMS_BEFORE.0.szContentSlug }}?p={{ ITEMS_BEFORE.0.pp }}&n={{ ITEMS_BEFORE.0.nn }}"><i class="bi bi-arrow-left" title="Предыдущая"></i></a></li>{% else %}<li class="page-item disabled"><a class="page-link" href="#"><i class="bi bi-arrow-left" title="Предыдущая"></i></a></li>{% endif %}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
{% load static %}{% load thumbnail %}{% load slug_ru %}<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<url><loc>https://cadpoint.ru/</loc><priority>1</priority></url>{% for I in ITEMS %}
|
||||
<url><loc>https://cadpoint.ru/item/{{ I.id }}-{{ I.szContentSlug }}</loc><priority>1</priority></url>{% endfor %}
|
||||
</urlset>
|
||||
64
cadpoint/web/sitemaps.py
Normal file
64
cadpoint/web/sitemaps.py
Normal file
@@ -0,0 +1,64 @@
|
||||
from django.contrib.sitemaps import Sitemap
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from django.db.models import Q
|
||||
from taggit.models import Tag
|
||||
|
||||
from web.models import TbContent
|
||||
|
||||
|
||||
class CadpointSitemap(Sitemap):
|
||||
"""Одна карта сайта для публичных страниц CADpoint."""
|
||||
|
||||
changefreq = 'weekly'
|
||||
|
||||
def items(self):
|
||||
now_value = timezone.now()
|
||||
content_items = list(
|
||||
TbContent.objects.filter(
|
||||
bContentPublish=True,
|
||||
tdContentPublishUp__lte=now_value,
|
||||
).filter(
|
||||
Q(tdContentPublishDown__isnull=True) | Q(tdContentPublishDown__gt=now_value)
|
||||
).order_by('-tdContentPublishUp', 'id')
|
||||
)
|
||||
latest_content = content_items[0].dtContentTimeStamp if content_items else None
|
||||
|
||||
sitemap_items = [
|
||||
{'kind': 'home', 'lastmod': latest_content},
|
||||
{'kind': 'alltags', 'lastmod': latest_content},
|
||||
]
|
||||
|
||||
tags = Tag.objects.filter(taggit_taggeditem_items__isnull=False).distinct().order_by('name')
|
||||
sitemap_items.extend({'kind': 'tag', 'tag': tag} for tag in tags)
|
||||
sitemap_items.extend({'kind': 'item', 'item': item} for item in content_items)
|
||||
return sitemap_items
|
||||
|
||||
def location(self, item):
|
||||
kind = item['kind']
|
||||
if kind == 'home':
|
||||
return '/'
|
||||
if kind == 'alltags':
|
||||
return reverse('web_alltags')
|
||||
if kind == 'tag':
|
||||
return f"/tag_{item['tag'].slug}"
|
||||
return f"/item/{item['item'].id}-{item['item'].szContentSlug}"
|
||||
|
||||
def lastmod(self, item):
|
||||
kind = item['kind']
|
||||
if kind in {'home', 'alltags'}:
|
||||
return item.get('lastmod')
|
||||
if kind == 'item':
|
||||
return item['item'].dtContentTimeStamp
|
||||
return None
|
||||
|
||||
def priority(self, item):
|
||||
kind = item['kind']
|
||||
if kind == 'home':
|
||||
return 1.0
|
||||
if kind == 'alltags':
|
||||
return 0.6
|
||||
if kind == 'tag':
|
||||
return 0.5
|
||||
return 0.8
|
||||
|
||||
@@ -82,6 +82,13 @@ class AdminTypographFormTests(SimpleTestCase):
|
||||
'html',
|
||||
)
|
||||
|
||||
for field_name in ('szContentKeywords', 'szContentDescription'):
|
||||
self.assertIsInstance(form.fields[field_name].widget, Textarea)
|
||||
self.assertNotEqual(
|
||||
form.fields[field_name].widget.attrs.get('data-codemirror-editor'),
|
||||
'1',
|
||||
)
|
||||
|
||||
self.assertIn('codemirror/editor.js', str(form.media))
|
||||
|
||||
def test_tbcontent_model_has_no_btypograf_field(self):
|
||||
@@ -181,6 +188,41 @@ class AllTagsPageTests(TestCase):
|
||||
self.assertContains(response, '<b class="_tag">1</b>')
|
||||
|
||||
|
||||
class TagEmptyStateTests(TestCase):
|
||||
def setUp(self):
|
||||
self.item = TbContent.objects.create(
|
||||
szContentHead='Тест 1',
|
||||
szContentIntro='Анонс 1',
|
||||
szContentBody='Тело 1',
|
||||
szContentSlug='test-1',
|
||||
bContentPublish=True,
|
||||
)
|
||||
self.item.tags.add('alpha')
|
||||
Tag.objects.create(name='lonely')
|
||||
|
||||
def test_tag_page_with_news_still_renders_entries(self):
|
||||
response = self.client.get('/tag_alpha')
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, 'Тест 1')
|
||||
self.assertNotContains(response, 'Новостей не найдено')
|
||||
|
||||
def test_tag_page_without_news_shows_empty_state(self):
|
||||
response = self.client.get('/tag_lonely')
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, 'Новостей не найдено')
|
||||
self.assertContains(response, 'По этому тегу пока нет опубликованных новостей.')
|
||||
self.assertNotContains(response, 'Тест 1')
|
||||
|
||||
def test_tag_page_for_missing_slug_shows_missing_tag_message(self):
|
||||
response = self.client.get('/tag_rebranded-tag')
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, 'Тег не найден')
|
||||
self.assertContains(response, 'не найден или был переименован')
|
||||
|
||||
|
||||
class TypographTests(TestCase):
|
||||
def test_save_generates_slug_from_clean_text(self):
|
||||
item = TbContent(szContentHead='<b>Привет мир</b>')
|
||||
@@ -277,16 +319,107 @@ class TypographTests(TestCase):
|
||||
szContentHead='Проверка просмотра',
|
||||
szContentIntro='Короткий анонс',
|
||||
szContentBody='Полный текст',
|
||||
szContentSlug='proverka-prosmotra',
|
||||
szContentSlug='real-slug',
|
||||
bContentPublish=True,
|
||||
)
|
||||
timestamp_before = item.dtContentTimeStamp
|
||||
|
||||
response = self.client.get(f'/item/{item.id}-{item.szContentSlug}')
|
||||
response = self.client.get(f'/item/{item.id}-wrong-slug')
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, '<title>Проверка просмотра | CADpoint</title>')
|
||||
self.assertContains(
|
||||
response,
|
||||
f'<link rel="canonical" href="http://testserver/item/{item.id}-{item.szContentSlug}" />',
|
||||
)
|
||||
self.assertNotContains(response, 'wrong-slug')
|
||||
self.assertContains(response, '<script type="application/ld+json">')
|
||||
self.assertContains(response, '"@type": "WebSite"')
|
||||
self.assertContains(response, '"@type": "Article"')
|
||||
self.assertRegex(
|
||||
response.content.decode(),
|
||||
r'"datePublished": "\d{4}-\d{2}-\d{2}T\d{2}:\d{2}[+-]\d{2}:\d{2}"',
|
||||
)
|
||||
self.assertRegex(
|
||||
response.content.decode(),
|
||||
r'"dateModified": "\d{4}-\d{2}-\d{2}T\d{2}:\d{2}[+-]\d{2}:\d{2}"',
|
||||
)
|
||||
item.refresh_from_db()
|
||||
self.assertEqual(item.iContentHits, 1)
|
||||
self.assertEqual(item.dtContentTimeStamp, timestamp_before)
|
||||
|
||||
def test_show_item_keywords_prioritize_explicit_seo_values(self):
|
||||
item = TbContent.objects.create(
|
||||
szContentHead='SEO ключи',
|
||||
szContentIntro='Анонс',
|
||||
szContentBody='Текст',
|
||||
szContentSlug='seo-klyuchi',
|
||||
szContentKeywords='ключ1, ключ2',
|
||||
bContentPublish=True,
|
||||
)
|
||||
item.tags.add('alpha', 'beta')
|
||||
|
||||
response = self.client.get(f'/item/{item.id}-{item.szContentSlug}')
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(
|
||||
response,
|
||||
'<meta name="keywords" content="cadpoint, ключ1, ключ2, alpha, beta, новости" />',
|
||||
)
|
||||
self.assertNotContains(response, 'None')
|
||||
|
||||
def test_show_item_keywords_without_explicit_value_do_not_render_none(self):
|
||||
item = TbContent.objects.create(
|
||||
szContentHead='SEO пусто',
|
||||
szContentIntro='Анонс',
|
||||
szContentBody='Текст',
|
||||
szContentSlug='seo-pusto',
|
||||
szContentKeywords=None,
|
||||
bContentPublish=True,
|
||||
)
|
||||
item.tags.add('alpha')
|
||||
|
||||
response = self.client.get(f'/item/{item.id}-{item.szContentSlug}')
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(
|
||||
response,
|
||||
'<meta name="keywords" content="cadpoint, alpha, новости" />',
|
||||
)
|
||||
self.assertNotContains(response, 'None')
|
||||
|
||||
|
||||
class SitemapTests(TestCase):
|
||||
def setUp(self):
|
||||
self.published = TbContent.objects.create(
|
||||
szContentHead='Опубликованная статья',
|
||||
szContentIntro='Анонс',
|
||||
szContentBody='Текст',
|
||||
szContentSlug='opublikovannaya-statya',
|
||||
bContentPublish=True,
|
||||
)
|
||||
self.published.tags.add('alpha')
|
||||
TbContent.objects.create(
|
||||
szContentHead='Скрытая статья',
|
||||
szContentIntro='Анонс',
|
||||
szContentBody='Текст',
|
||||
szContentSlug='skrytaya-statya',
|
||||
bContentPublish=False,
|
||||
)
|
||||
|
||||
def test_sitemap_uses_django_framework_and_lists_public_pages(self):
|
||||
response = self.client.get(reverse('web_sitemap'))
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, '<?xml version="1.0" encoding="UTF-8"?>', html=False)
|
||||
self.assertContains(response, '<loc>http://testserver/</loc>', html=False)
|
||||
self.assertContains(response, '<loc>http://testserver/alltags</loc>', html=False)
|
||||
self.assertContains(
|
||||
response,
|
||||
f'<loc>http://testserver/item/{self.published.id}-{self.published.szContentSlug}</loc>',
|
||||
html=False,
|
||||
)
|
||||
self.assertContains(response, '<loc>http://testserver/tag_alpha</loc>', html=False)
|
||||
self.assertNotContains(response, 'skrytaya-statya')
|
||||
|
||||
|
||||
|
||||
@@ -90,6 +90,8 @@ def index(request,
|
||||
"""
|
||||
template = "index.jinja2" # шаблон
|
||||
to_template: dict[str, object] = {"COOKIES": check_cookies(request)}
|
||||
empty_state_title = ""
|
||||
empty_state_message = ""
|
||||
page_number = max(int(ppage), 0)
|
||||
now_value = timezone.now()
|
||||
|
||||
@@ -109,6 +111,7 @@ def index(request,
|
||||
# Список тегов должен быть отсортированным для канонического URL.
|
||||
return HttpResponseRedirect("tag_%s" % "_".join(sorted(selected_tags)))
|
||||
content_qs = content_qs.filter(tags__slug__in=selected_tags).distinct()
|
||||
to_template["SELECTED_TAGS"] = Tag.objects.filter(slug__in=selected_tags).order_by("slug")
|
||||
to_template["TAGS_S"] = "/tag_" + slug_tags
|
||||
to_template["TAGS_L"] = selected_tags
|
||||
|
||||
@@ -116,6 +119,26 @@ def index(request,
|
||||
total_items = q_content.count()
|
||||
total_page = max(math.ceil(total_items / settings.NUM_ITEMS_IN_PAGE) - 1, 0) if total_items else 0
|
||||
|
||||
if selected_tags:
|
||||
existing_tags = set(Tag.objects.filter(slug__in=selected_tags).values_list("slug", flat=True))
|
||||
missing_tags = [tag_slug for tag_slug in selected_tags if tag_slug not in existing_tags]
|
||||
if missing_tags:
|
||||
if len(missing_tags) == 1:
|
||||
empty_state_title = "Тег не найден"
|
||||
empty_state_message = f"Тег «{missing_tags[0]}» не найден или был переименован."
|
||||
else:
|
||||
empty_state_title = "Теги не найдены"
|
||||
empty_state_message = f"Теги «{', '.join(missing_tags)}» не найдены или были переименованы."
|
||||
elif not total_items:
|
||||
if len(selected_tags) == 1:
|
||||
empty_state_message = "По этому тегу пока нет опубликованных новостей."
|
||||
else:
|
||||
empty_state_message = "По выбранным тегам пока нет опубликованных новостей."
|
||||
elif page_number > total_page:
|
||||
empty_state_message = "На этой странице больше нет новостей. Откройте первую страницу ленты."
|
||||
elif not total_items:
|
||||
empty_state_message = "Пока здесь нет новостей."
|
||||
|
||||
q_content = q_content[page_number * settings.NUM_ITEMS_IN_PAGE:
|
||||
page_number * settings.NUM_ITEMS_IN_PAGE+ settings.NUM_ITEMS_IN_PAGE]
|
||||
|
||||
@@ -138,6 +161,8 @@ def index(request,
|
||||
to_template["TAGS_IN_PAGE"] = q_tags
|
||||
to_template["PAGE_OF_LIST"] = page_number
|
||||
to_template["TOTAL_PAGE"] = total_page
|
||||
to_template["EMPTY_STATE_TITLE"] = empty_state_title
|
||||
to_template["EMPTY_STATE_MESSAGE"] = empty_state_message
|
||||
return render(request, template, to_template)
|
||||
|
||||
|
||||
@@ -223,16 +248,3 @@ def show_item(request,
|
||||
except (ValueError, AttributeError, TbContent.DoesNotExist, TbContent.MultipleObjectsReturned):
|
||||
raise Http404("Контента с таким id не существует")
|
||||
|
||||
|
||||
def sitemap(request):
|
||||
template = "sitemap.jinja2" # шаблон
|
||||
q_items = TbContent.objects.filter(
|
||||
bContentPublish=True,
|
||||
tdContentPublishUp__lte=timezone.now(),
|
||||
).filter(
|
||||
Q(tdContentPublishDown__isnull=True) | Q(tdContentPublishDown__gt=timezone.now())
|
||||
).order_by("-tdContentPublishUp", "id").all()
|
||||
to_template: dict[str, object] = {"ITEMS": q_items}
|
||||
print(q_items)
|
||||
response = render(request, template, to_template)
|
||||
return response
|
||||
|
||||
19
public/llms.txt
Normal file
19
public/llms.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
# CADpoint
|
||||
|
||||
CADpoint — русскоязычный сайт о 3D-печати, CAD и смежных темах.
|
||||
|
||||
## Основные страницы
|
||||
- https://cadpoint.ru/ — главная лента новостей и публикаций
|
||||
- https://cadpoint.ru/alltags — список всех тегов (тем) сайта
|
||||
- https://cadpoint.ru/sitemap.xml — полный список опубликованных страниц
|
||||
|
||||
## Страницы контента
|
||||
- https://cadpoint.ru/item/<id>-<slug> — статья или публикация
|
||||
- https://cadpoint.ru/tag_<slug> — страницы с материалами по тематическому тегу
|
||||
|
||||
## Как ориентироваться
|
||||
- Основной контент на русском языке.
|
||||
- Приоритет отдавайте публичным страницам статей и тегов.
|
||||
- Админка, debug-URL и служебные страницы не являются основным контентом.
|
||||
- Для ссылок используйте канонические публичные URL без служебных параметров.
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
# robots.txt for CADpoint
|
||||
|
||||
User-agent: *
|
||||
Disallow: /admin/
|
||||
Clean-param: ref /item/
|
||||
# Оставляем только нужное: игнорируем параметр `p` и 'n' у страниц статей.
|
||||
Clean-param: p&n /item/
|
||||
|
||||
# подсказываем карту сайта и основной хост.
|
||||
Sitemap: https://cadpoint.ru/sitemap.xml
|
||||
Host: cadpoint.ru
|
||||
|
||||
# Ссылка на файл для ИИ-моделей: https://cadpoint.ru/llms.txt
|
||||
|
||||
Reference in New Issue
Block a user