Оптимизация под поисковую выдачу
This commit is contained in:
parent
32b1ec4379
commit
cfd318955b
Binary file not shown.
@ -40,6 +40,8 @@ INSTALLED_APPS = [
|
|||||||
'programmer.apps.ProgrammerConfig',
|
'programmer.apps.ProgrammerConfig',
|
||||||
'django_bootstrap5',
|
'django_bootstrap5',
|
||||||
'django_extensions',
|
'django_extensions',
|
||||||
|
'django.contrib.sites',
|
||||||
|
'django.contrib.sitemaps',
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
|
|||||||
Binary file not shown.
BIN
OneCprogsite/programmer/__pycache__/sitemaps.cpython-310.pyc
Normal file
BIN
OneCprogsite/programmer/__pycache__/sitemaps.cpython-310.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
0
OneCprogsite/programmer/management/__init__.py
Normal file
0
OneCprogsite/programmer/management/__init__.py
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
27
OneCprogsite/programmer/management/commands/test_sitemap.py
Normal file
27
OneCprogsite/programmer/management/commands/test_sitemap.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from django.contrib.sitemaps import Sitemap
|
||||||
|
from django.urls import reverse
|
||||||
|
from programmer.models import Home, Solution, Competence, Recall
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = 'Test sitemap generation'
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
from programmer.sitemaps import sitemaps
|
||||||
|
|
||||||
|
self.stdout.write('Testing sitemap generation...')
|
||||||
|
|
||||||
|
for name, sitemap in sitemaps.items():
|
||||||
|
self.stdout.write(f'\n{name}:')
|
||||||
|
items = sitemap().items()
|
||||||
|
self.stdout.write(f' Items found: {len(items)}')
|
||||||
|
|
||||||
|
for item in items[:3]: # Показываем первые 3 элемента
|
||||||
|
try:
|
||||||
|
url = sitemap().location(item)
|
||||||
|
self.stdout.write(f' - {url}')
|
||||||
|
except Exception as e:
|
||||||
|
self.stdout.write(f' - Error: {e}')
|
||||||
|
|
||||||
|
self.stdout.write('\nSitemap test completed!')
|
||||||
@ -1,6 +1,9 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
from django.db.models.signals import post_save, post_delete
|
||||||
|
from django.dispatch import receiver
|
||||||
|
from django.core.cache import cache
|
||||||
|
|
||||||
|
|
||||||
class Recall(models.Model):
|
class Recall(models.Model):
|
||||||
@ -125,3 +128,12 @@ class Visitor(models.Model):
|
|||||||
indexes = [
|
indexes = [
|
||||||
models.Index(fields=['ip_address']),
|
models.Index(fields=['ip_address']),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@receiver([post_save, post_delete], sender=Home)
|
||||||
|
@receiver([post_save, post_delete], sender=Solution)
|
||||||
|
@receiver([post_save, post_delete], sender=Competence)
|
||||||
|
@receiver([post_save, post_delete], sender=Recall)
|
||||||
|
def clear_sitemap_cache(sender, **kwargs):
|
||||||
|
"""Очищаем кэш sitemap при изменении контента"""
|
||||||
|
cache.delete('sitemap_cache')
|
||||||
|
|||||||
64
OneCprogsite/programmer/sitemaps.py
Normal file
64
OneCprogsite/programmer/sitemaps.py
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
from django.contrib.sitemaps import Sitemap
|
||||||
|
from django.urls import reverse
|
||||||
|
from .models import Home, Solution, Competence, Recall
|
||||||
|
|
||||||
|
class StaticViewSitemap(Sitemap):
|
||||||
|
priority = 1.0
|
||||||
|
changefreq = 'monthly'
|
||||||
|
|
||||||
|
def items(self):
|
||||||
|
return ['home', 'about', 'solution', 'ability', 'recall']
|
||||||
|
|
||||||
|
def location(self, item):
|
||||||
|
return reverse(item)
|
||||||
|
|
||||||
|
class HomeSitemap(Sitemap):
|
||||||
|
changefreq = 'weekly'
|
||||||
|
priority = 1.0
|
||||||
|
|
||||||
|
def items(self):
|
||||||
|
return Home.objects.filter(is_published=True)
|
||||||
|
|
||||||
|
def lastmod(self, obj):
|
||||||
|
return obj.time_update
|
||||||
|
|
||||||
|
# УБИРАЕМ метод location - используем default
|
||||||
|
# Django автоматически сгенерирует правильные URL
|
||||||
|
|
||||||
|
class SolutionSitemap(Sitemap):
|
||||||
|
changefreq = 'weekly'
|
||||||
|
priority = 0.9
|
||||||
|
|
||||||
|
def items(self):
|
||||||
|
return Solution.objects.filter(is_published=True)
|
||||||
|
|
||||||
|
def lastmod(self, obj):
|
||||||
|
return obj.time_update
|
||||||
|
|
||||||
|
class CompetenceSitemap(Sitemap):
|
||||||
|
changefreq = 'monthly'
|
||||||
|
priority = 0.8
|
||||||
|
|
||||||
|
def items(self):
|
||||||
|
return Competence.objects.filter(is_published=True)
|
||||||
|
|
||||||
|
def lastmod(self, obj):
|
||||||
|
return obj.time_update
|
||||||
|
|
||||||
|
class RecallSitemap(Sitemap):
|
||||||
|
changefreq = 'monthly'
|
||||||
|
priority = 0.7
|
||||||
|
|
||||||
|
def items(self):
|
||||||
|
return Recall.objects.filter(is_published=True)
|
||||||
|
|
||||||
|
def lastmod(self, obj):
|
||||||
|
return obj.time_update
|
||||||
|
|
||||||
|
# Упрощаем sitemaps - убираем HomeSitemap если он дублирует главную
|
||||||
|
sitemaps = {
|
||||||
|
'static': StaticViewSitemap,
|
||||||
|
'solutions': SolutionSitemap,
|
||||||
|
'competence': CompetenceSitemap,
|
||||||
|
'recall': RecallSitemap,
|
||||||
|
}
|
||||||
@ -118,4 +118,37 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script type="application/ld+json">
|
||||||
|
{
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "Service",
|
||||||
|
"serviceType": "1С программирование",
|
||||||
|
"provider": {
|
||||||
|
"@type": "Person",
|
||||||
|
"name": "Николай Сердюк"
|
||||||
|
},
|
||||||
|
"areaServed": "Россия",
|
||||||
|
"hasOfferCatalog": {
|
||||||
|
"@type": "OfferCatalog",
|
||||||
|
"name": "Услуги программиста 1С",
|
||||||
|
"itemListElement": [
|
||||||
|
{
|
||||||
|
"@type": "Offer",
|
||||||
|
"itemOffered": {
|
||||||
|
"@type": "Service",
|
||||||
|
"name": "Разработка конфигураций 1С"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "Offer",
|
||||||
|
"itemOffered": {
|
||||||
|
"@type": "Service",
|
||||||
|
"name": "Интеграция 1С с веб-сервисами"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -5,6 +5,28 @@
|
|||||||
<html lang="ru">
|
<html lang="ru">
|
||||||
<head>
|
<head>
|
||||||
<title>{{title}} - Программист 1С</title>
|
<title>{{title}} - Программист 1С</title>
|
||||||
|
<!-- Основные мета-теги -->
|
||||||
|
<meta name="description" content="{% block meta_description %}Профессиональный программист 1С с более чем 10-летним опытом. Разработка, интеграция и оптимизация систем 1С.{% endblock %}">
|
||||||
|
<meta name="keywords" content="{% block meta_keywords %}программист 1С, разработка 1С, интеграция 1С, оптимизация 1С, 1С предприятие{% endblock %}">
|
||||||
|
<meta name="author" content="Николай Сердюк">
|
||||||
|
|
||||||
|
<!-- Open Graph для соцсетей -->
|
||||||
|
<meta property="og:title" content="{{title}} - Программист 1С">
|
||||||
|
<meta property="og:description" content="Профессиональный программист 1С с более чем 10-летним опытом">
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta property="og:url" content="{{ request.build_absolute_uri }}">
|
||||||
|
<meta property="og:image" content="{% static 'programmer/images/og-image.jpg' %}">
|
||||||
|
<meta property="og:site_name" content="Программист 1С - Николай Сердюк">
|
||||||
|
|
||||||
|
<!-- Twitter Card -->
|
||||||
|
<meta name="twitter:card" content="summary_large_image">
|
||||||
|
<meta name="twitter:title" content="{{title}} - Программист 1С">
|
||||||
|
<meta name="twitter:description" content="Профессиональный программист 1С с более чем 10-летним опытом">
|
||||||
|
<meta name="twitter:image" content="{% static 'programmer/images/og-image.jpg' %}">
|
||||||
|
|
||||||
|
<!-- Дополнительные SEO-теги -->
|
||||||
|
<meta name="robots" content="index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1">
|
||||||
|
<link rel="canonical" href="{{ request.build_absolute_uri }}">
|
||||||
{% bootstrap_css %}
|
{% bootstrap_css %}
|
||||||
|
|
||||||
<!-- Основной CSS файл (темная тема по умолчанию) -->
|
<!-- Основной CSS файл (темная тема по умолчанию) -->
|
||||||
@ -339,6 +361,58 @@
|
|||||||
{% block extra_css %}
|
{% block extra_css %}
|
||||||
<!-- Дополнительные CSS файлы для конкретных страниц -->
|
<!-- Дополнительные CSS файлы для конкретных страниц -->
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
<!-- Google Analytics -->
|
||||||
|
<script async src="https://www.googletagmanager.com/gtag/js?id=G-X3W9YSQHRM"></script>
|
||||||
|
<script>
|
||||||
|
window.dataLayer = window.dataLayer || [];
|
||||||
|
function gtag(){dataLayer.push(arguments);}
|
||||||
|
gtag('js', new Date());
|
||||||
|
|
||||||
|
gtag('config', 'G-X3W9YSQHRM');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Яндекс.Метрика -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
(function(m,e,t,r,i,k,a){
|
||||||
|
m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
|
||||||
|
m[i].l=1*new Date();
|
||||||
|
for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }}
|
||||||
|
k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)
|
||||||
|
})(window, document,'script','https://mc.yandex.ru/metrika/tag.js?id=105278924', 'ym');
|
||||||
|
|
||||||
|
ym(105278924, 'init', {ssr:true, webvisor:true, clickmap:true, ecommerce:"dataLayer", accurateTrackBounce:true, trackLinks:true});
|
||||||
|
</script>
|
||||||
|
<noscript><div><img src="https://mc.yandex.ru/watch/105278924" style="position:absolute; left:-9999px;" alt="" /></div></noscript>
|
||||||
|
|
||||||
|
<script type="application/ld+json">
|
||||||
|
{
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "Person",
|
||||||
|
"name": "Николай Сердюк",
|
||||||
|
"jobTitle": "Программист 1С",
|
||||||
|
"description": "Профессиональный программист 1С с более чем 10-летним опытом",
|
||||||
|
"url": "https://nikdizell.ru",
|
||||||
|
"email": "{{ CONTACT_EMAIL }}",
|
||||||
|
"telephone": "{{ CONTACT_PHONE }}",
|
||||||
|
"knowsAbout": [
|
||||||
|
"1С:Предприятие 8.3",
|
||||||
|
"Управление торговлей",
|
||||||
|
"Бухгалтерия предприятия",
|
||||||
|
"Зарплата и управление персоналом",
|
||||||
|
"SQL",
|
||||||
|
"Веб-сервисы",
|
||||||
|
"API интеграция"
|
||||||
|
],
|
||||||
|
"hasOccupation": {
|
||||||
|
"@type": "Occupation",
|
||||||
|
"name": "Программист 1С",
|
||||||
|
"description": "Разработка и сопровождение систем на платформе 1С",
|
||||||
|
"occupationLocation": "Россия"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
|
|||||||
13
OneCprogsite/programmer/templates/programmer/humans.txt
Normal file
13
OneCprogsite/programmer/templates/programmer/humans.txt
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/* TEAM */
|
||||||
|
Developer: Николай Сердюк
|
||||||
|
Site: https://nikdizell.ru
|
||||||
|
Email: {{ CONTACT_EMAIL }}
|
||||||
|
|
||||||
|
/* THANKS */
|
||||||
|
Django Framework
|
||||||
|
Bootstrap
|
||||||
|
|
||||||
|
/* SITE */
|
||||||
|
Last update: 2025
|
||||||
|
Language: Russian
|
||||||
|
Doctype: HTML5
|
||||||
18
OneCprogsite/programmer/templates/programmer/robots.txt
Normal file
18
OneCprogsite/programmer/templates/programmer/robots.txt
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
User-agent: *
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
# Основной сайт
|
||||||
|
Sitemap: {{ request.scheme }}://{{ request.get_host }}/sitemap.xml
|
||||||
|
|
||||||
|
# Запрещаем служебные разделы
|
||||||
|
Disallow: /admin/
|
||||||
|
Disallow: /static/admin/
|
||||||
|
Disallow: /callback/
|
||||||
|
Disallow: /api/
|
||||||
|
|
||||||
|
# Разрешаем индексацию статических файлов
|
||||||
|
Allow: /static/
|
||||||
|
Allow: /media/
|
||||||
|
|
||||||
|
# Указываем главное зеркало
|
||||||
|
Host: {{ request.scheme }}://{{ request.get_host }}
|
||||||
12
OneCprogsite/programmer/templates/programmer/sitemap.xml
Normal file
12
OneCprogsite/programmer/templates/programmer/sitemap.xml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
||||||
|
xmlns:xhtml="http://www.w3.org/1999/xhtml">
|
||||||
|
{% for url in urlset %}
|
||||||
|
<url>
|
||||||
|
<loc>{{ url.location }}</loc>
|
||||||
|
{% if url.lastmod %}<lastmod>{{ url.lastmod|date:"Y-m-d" }}</lastmod>{% endif %}
|
||||||
|
{% if url.changefreq %}<changefreq>{{ url.changefreq }}</changefreq>{% endif %}
|
||||||
|
{% if url.priority %}<priority>{{ url.priority }}</priority>{% endif %}
|
||||||
|
</url>
|
||||||
|
{% endfor %}
|
||||||
|
</urlset>
|
||||||
@ -3,6 +3,9 @@ from django.urls import path, include
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.conf.urls.static import static
|
from django.conf.urls.static import static
|
||||||
from .views import *
|
from .views import *
|
||||||
|
from django.contrib.sitemaps.views import sitemap
|
||||||
|
from .sitemaps import sitemaps
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', index, name='home'),
|
path('', index, name='home'),
|
||||||
@ -13,7 +16,12 @@ urlpatterns = [
|
|||||||
path('post/<int:post_id>/', show_post, name='post'),
|
path('post/<int:post_id>/', show_post, name='post'),
|
||||||
path('callback/', callback_request, name='callback'),
|
path('callback/', callback_request, name='callback'),
|
||||||
path('admin/statistics/', statistics_view, name='statistics'),
|
path('admin/statistics/', statistics_view, name='statistics'),
|
||||||
|
# Sitemap
|
||||||
|
path('sitemap.xml', sitemap, {'sitemaps': sitemaps},
|
||||||
|
name='django.contrib.sitemaps.views.sitemap'),
|
||||||
|
path('robots.txt', robots_txt, name='robots'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
@ -9,6 +9,7 @@ from datetime import timedelta
|
|||||||
from .models import PageView, Visitor
|
from .models import PageView, Visitor
|
||||||
from django.db.models import Count
|
from django.db.models import Count
|
||||||
from django.contrib.auth.decorators import login_required, user_passes_test
|
from django.contrib.auth.decorators import login_required, user_passes_test
|
||||||
|
from django.views.decorators.http import require_GET
|
||||||
|
|
||||||
|
|
||||||
menu = [
|
menu = [
|
||||||
@ -107,6 +108,8 @@ def index(request):
|
|||||||
'posts': posts,
|
'posts': posts,
|
||||||
'menu': menu,
|
'menu': menu,
|
||||||
'title': "Главная страница",
|
'title': "Главная страница",
|
||||||
|
'meta_description': "Профессиональный программист 1С с более чем 10-летним опытом. Разработка, интеграция и оптимизация систем 1С. Закажите консультацию.",
|
||||||
|
'meta_keywords': "программист 1С, разработка 1С, интеграция 1С, оптимизация 1С, 1С предприятие 8.3",
|
||||||
'form': CallbackForm()
|
'form': CallbackForm()
|
||||||
}
|
}
|
||||||
return render(request, 'programmer/index.html', context=context)
|
return render(request, 'programmer/index.html', context=context)
|
||||||
@ -116,7 +119,9 @@ def index(request):
|
|||||||
def about(request):
|
def about(request):
|
||||||
context = {
|
context = {
|
||||||
'menu': menu,
|
'menu': menu,
|
||||||
'title': "Обо мне"
|
'title': "Обо мне - Программист 1С",
|
||||||
|
'meta_description': "Николай Сердюк - профессиональный программист 1С с более чем 10-летним опытом. Разработка, интеграция, оптимизация бизнес-процессов.",
|
||||||
|
'meta_keywords': "программист 1С Николай Сердюк, опыт работы 1С, компетенции 1С, проекты 1С"
|
||||||
}
|
}
|
||||||
return render(request, 'programmer/about.html', context=context)
|
return render(request, 'programmer/about.html', context=context)
|
||||||
|
|
||||||
@ -233,3 +238,8 @@ def statistics_view(request):
|
|||||||
}
|
}
|
||||||
|
|
||||||
return render(request, 'admin/statistics.html', context)
|
return render(request, 'admin/statistics.html', context)
|
||||||
|
|
||||||
|
|
||||||
|
@require_GET
|
||||||
|
def robots_txt(request):
|
||||||
|
return render(request, 'robots.txt', content_type='text/plain')
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user