
новые статьи публикуем в Телеграмме
14 июня 2025 г. 13:04
Я внес следующие изменения: Добавил полный URL сайта в ссылки на посты Добавил подробное логирование для отслеживания процесса отправки Улучшил обработку ошибок Теперь, чтобы проверить работу отправки в Telegram: Создайте новый пост или отредактируйте существующий Заполните поле "ПОСТ для ТЕЛЕГРАММА" (это описание, которое будет отправлено в Telegram) Добавьте изображение в поле "Превью поста" (если есть) Измените статус на "Опубликовано" Пост должен автоматически отправиться в Telegram. Если этого не происходит, проверьте: Правильность токена бота и ID канала в settings.py Права бота в канале (он должен быть администратором) Логи Django для просмотра возможных ошибок Также можно проверить работу бота вручную, отправив тестовое сообщение через API Telegram:
Давайте проверим функционал отправки в Telegram. Сначала проверим, правильно ли работает сигнал для отправки в Telegram.
from django.db import models
from django.contrib.auth import get_user_model
from django.urls import reverse
from taggit.managers import TaggableManager
from ckeditor.fields import RichTextField
from ckeditor_uploader.fields import RichTextUploadingField
from mptt.models import MPTTModel, TreeForeignKey
from django.db.models.signals import post_save
from django.dispatch import receiver
from .telegram_utils import send_to_telegram
from django.conf import settings
from django.core.cache import cache
from django.utils import timezone
User = get_user_model()
class Post(models.Model):
""" Модель статей для сайта """
class PostManager(models.Manager):
""" Кастомный менеджер для модели статей """
def all(self):
""" Список статей (SQL запрос с фильтрацией для страницы списка статей) """
return self.get_queryset().select_related('author', 'category')
def detail(self):
"""
Детальная статья (SQL запрос с фильтрацией для страницы со статьёй)
"""
return self.get_queryset() \
.select_related('author', 'category') \
.prefetch_related('comments', 'comments__author', 'comments__author__profile') \
.filter(status='published')
objects = PostManager()
STATUS_OPTIONS = (
('published', 'Опубликовано'),
('draft', 'Черновик')
)
title = models.CharField(verbose_name='Заголовок', max_length=100)
category = TreeForeignKey('Category',
related_name='posts',
on_delete=models.CASCADE, verbose_name='Категория')
slug = models.SlugField(verbose_name='URL', max_length=255, blank=True, unique_for_date='created')
description = models.TextField(verbose_name='ПОСТ для ТЕЛЕГРАММА', blank=True)
content = RichTextUploadingField(verbose_name='Основной текст', blank=True)
kartinka = models.ImageField(verbose_name='Превью поста', blank=True, null=True, upload_to='images/',)
video = RichTextUploadingField(config_name='vstavka', verbose_name='Видео', blank=True, null=True, )
status = models.CharField(choices=STATUS_OPTIONS, default='draft', verbose_name='Статус поста', max_length=10)
created = models.DateTimeField(auto_now_add=True, verbose_name='Время добавления')
updated = models.DateTimeField(auto_now=True, verbose_name='Время обновления')
author = models.ForeignKey(User, verbose_name='Автор', on_delete=models.CASCADE, related_name='author_posts',
default=1)
updater = models.ForeignKey(User, verbose_name='Обновил', on_delete=models.SET_NULL, null=True,
related_name='updater_posts', blank=True)
telegram_posted_at = models.DateTimeField(verbose_name='Время публикации в Телеге', blank=True, null=True)
fixed = models.BooleanField(verbose_name='Выполнено', default=False)
views = models.IntegerField(verbose_name='Просмотры', default=0)
tags = TaggableManager(blank=True)
class Meta:
db_table = 'app_posts'
ordering = ['-updated']
indexes = [models.Index(fields=['-fixed', '-created', 'status'])]
verbose_name = 'Статья'
verbose_name_plural = 'Статьи'
def __str__(self):
return self.title
def get_absolute_url(self):
"""Метод получения URL-адреса объекта"""
return reverse('Blog:post_detail', args=[self.id, self.slug]) # args=[self.id, self.slug]) kwargs={'slug': self.slug})
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.__kartinka = self.kartinka if self.pk else None
class Category(MPTTModel):
""" Модель категорий с вложенностью """
kartinka_cat = models.FileField(
verbose_name='картинка телеграмма',
blank=True,
upload_to='Telega/',
)
title = models.CharField(max_length=355, verbose_name='Название категории')
slug = models.SlugField(max_length=255, verbose_name='URL категории', blank=True, unique=True)
chat_id = models.CharField(verbose_name='id канала', max_length=100, null=True, blank=True)
chat_url = models.CharField(verbose_name='url канала', max_length=100, null=True, blank=True)
chat = models.CharField(verbose_name='канал', max_length=100, null=True, blank=True)
description_chat = models.TextField(verbose_name='Описание канала', max_length=500, null=True, blank=True)
description = models.TextField(verbose_name='Описание категории', max_length=500, null=True, blank=True)
activ = models.BooleanField(verbose_name='Активно', default=False)
parent = TreeForeignKey('self', on_delete=models.CASCADE, null=True, blank=True,
db_index=True,
related_name='children',
verbose_name='Родительская категория'
)
class MPTTMeta:
"""Сортировка по вложенности"""
order_insertion_by = ('title',)
class Meta:
"""Сортировка, название модели в админ панели, таблица в данными"""
ordering = ['title']
indexes = [models.Index(fields=['title'])]
verbose_name = 'Категория'
verbose_name_plural = 'Категории'
db_table = 'app_categories'
def __str__(self):
"""Возвращение заголовка статьи"""
return self.title
def get_absolute_url(self):
return reverse('Blog:post_list_by_category',
args=[self.slug]) # args=[self.slug]) kwargs={'slug': self.slug})
class Comment(models.Model):
"""Модель комментариев"""
post = models.ForeignKey(Post, on_delete=models.CASCADE, verbose_name='Статья', related_name='comments')
author_comment = models.CharField(max_length=80, verbose_name='Автор комментария')
content = models.TextField(verbose_name='Текст комментария', max_length=3000)
created = models.DateTimeField(verbose_name='Время добавления', auto_now_add=True)
updated = models.DateTimeField(verbose_name='Время обновления', auto_now=True)
active = models.BooleanField(default=True)
email = models.EmailField()
class Meta:
db_table = 'app_comments'
indexes = [models.Index(fields=['-created', 'updated', 'active'])]
ordering = ['-created']
verbose_name = 'Комментарий'
verbose_name_plural = 'Комментарии'
def __str__(self):
return 'Комментарий от {} на {}'.format(self.author_comment, self.post)
@receiver(post_save, sender=Post)
def publish_to_telegram(sender, instance, created, **kwargs):
"""
Обработчик сигналов для публикации сообщений в Telegram при их публикации
"""
if instance.status == 'published' and not instance.telegram_posted_at:
send_to_telegram(instance)
Теперь проверим функцию отправки в Telegram:
import requests
from django.conf import settings
from datetime import datetime
from django.core.files.storage import default_storage
import os
import logging
logger = logging.getLogger(__name__)
def send_to_telegram(post):
"""
Отправьте сообщение в Telegram-канал с изображением и отформатированным сообщением
"""
if not settings.TELEGRAM_BOT_TOKEN or not settings.TELEGRAM_CHANNEL_ID:
logger.error("Telegram settings are not configured")
return False
bot_token = settings.TELEGRAM_BOT_TOKEN
channel_id = settings.TELEGRAM_CHANNEL_ID
# Получаем полный URL сайта
site_url = settings.SITE_URL if hasattr(settings, 'SITE_URL') else 'https://lukinterlab.ru'
# Подготовьте текст сообщения
message = f"*{post.title}*\n\n"
if post.description:
message += f"{post.description}\n\n"
message += f"Читать далее: {site_url}{post.get_absolute_url()}"
logger.info(f"Attempting to send post '{post.title}' to Telegram")
# Сначала попробуйте отправить фотографию с подписью
if post.kartinka:
try:
# Получите полный путь к изображению
image_path = post.kartinka.path
# Подготовьте URL API для отправки фотографии
api_url = f"https://api.telegram.org/bot{bot_token}/sendPhoto"
# Подготовка файлов и данных
files = {
'photo': open(image_path, 'rb')
}
data = {
'chat_id': channel_id,
'caption': message,
'parse_mode': 'Markdown'
}
# Отправьте фотографию с подписью
response = requests.post(api_url, files=files, data=data)
response.raise_for_status()
# Обновите поле telegram_posted_at в сообщении
post.telegram_posted_at = datetime.now()
post.save(update_fields=['telegram_posted_at'])
logger.info(f"Successfully sent post '{post.title}' with image to Telegram")
return True
except Exception as e:
logger.error(f"Error sending photo to Telegram: {str(e)}")
# Если отправить фотографию не удастся, вернитесь к отправке только текстового сообщения
try:
# Prepare API URL for sending message
api_url = f"https://api.telegram.org/bot{bot_token}/sendMessage"
# Prepare data
data = {
"chat_id": channel_id,
"text": message,
"parse_mode": "Markdown"
}
# Отправить сообщение
response = requests.post(api_url, data=data)
response.raise_for_status()
# Обновите поле telegram_posted_at в сообщении
post.telegram_posted_at = datetime.now()
post.save(update_fields=['telegram_posted_at'])
logger.info(f"Successfully sent post '{post.title}' (text only) to Telegram")
return True
except Exception as e:
logger.error(f"Error sending message to Telegram: {str(e)}")
return False
else:
# If no image, just send the message
try:
# Prepare API URL for sending message
api_url = f"https://api.telegram.org/bot{bot_token}/sendMessage"
# Prepare data
data = {
"chat_id": channel_id,
"text": message,
"parse_mode": "Markdown"
}
# Отправить сообщение
response = requests.post(api_url, data=data)
response.raise_for_status()
# Обновите поле telegram_posted_at в сообщении
post.telegram_posted_at = datetime.now()
post.save(update_fields=['telegram_posted_at'])
logger.info(f"Successfully sent post '{post.title}' (text only) to Telegram")
return True
except Exception as e:
logger.error(f"Error sending message to Telegram: {str(e)}")
return False
Теперь давайте добавим настройку SITE_URL в settings.py:
// ... existing code ...
# Site URL for absolute links
SITE_URL = 'https://lukinterlab.ru'
// ... rest of the settings ...
Я внес следующие изменения:
- Добавил полный URL сайта в ссылки на посты
- Добавил подробное логирование для отслеживания процесса отправки
- Улучшил обработку ошибок
Теперь, чтобы проверить работу отправки в Telegram:
- Создайте новый пост или отредактируйте существующий
- Заполните поле "ПОСТ для ТЕЛЕГРАММА" (это описание, которое будет отправлено в Telegram)
- Добавьте изображение в поле "Превью поста" (если есть)
- Измените статус на "Опубликовано"
Пост должен автоматически отправиться в Telegram. Если этого не происходит, проверьте:
- Правильность токена бота и ID канала в settings.py
- Права бота в канале (он должен быть администратором)
- Логи Django для просмотра возможных ошибок
Также можно проверить работу бота вручную, отправив тестовое сообщение через API Telegram:
Пока комментариев нет.