Запуск telegram-бота на проекте django
Я разрабатываю проект djnago и хочу подключить к нему telegram-бота. Я использую python-telegram-bot
, но не знаю, как запустить бота при запуске сервера django.
from django.apps import AppConfig
from .telegramBot import updater
class SocialMediaConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'memefinder'
def ready(self) -> None:
updater.start_polling()
pass
Я добавил этот код в файл apps.py
одного из приложений проекта, но он не работает. Я получаю это сообщение об ошибке каждый раз, когда запускаю проект
telegram.error.Conflict: Conflict: terminated by other getUpdates request; make sure that only one bot instance is running
и это код файла telegramBot.py
. это очень простой код.
from telegram import Update, ForceReply
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters, CallbackContext
updater = Updater("TOKEN")
dispatcher = updater.dispatcher
def start(update: Update, context: CallbackContext) -> None:
"""Send a message when the command /start is issued."""
user = update.effective_user
update.message.reply_markdown_v2(
fr'Hi {user.mention_markdown_v2()}\!',
reply_markup=ForceReply(selective=True),
)
dispatcher.add_handler(CommandHandler("start", start))
Похоже, что проблема заключается в автозагрузчике Django. Когда выполняется команда manage.py runserver
, она порождает два экземпляра. Один - процесс мониторинга файлов, который перезагружает проект каждый раз, когда в одном из файлов проекта происходит какое-то изменение, а второй - основной процесс. Подробнее об этом можно прочитать здесь в этой статье.
Чтобы обойти это, нужно проверять и загружать процесс только тогда, когда программа запускается главным процессом, что можно сделать, проверив переменную окружения 'RUN_MAIN':
Home/apps.py:
from django.apps import AppConfig
class HomeConfig(AppConfig): name = 'Home'
def ready(self):
import os
from . import jobs
# RUN_MAIN check to avoid running the code twice since manage.py runserver runs 'ready' twice on startup
if os.environ.get('RUN_MAIN', None) != 'true':
# Your function to run the bot goes here
В примере выше предполагается, что у вас есть приложение под названием Home, в котором находится app.py.
На самом деле, лучшее решение здесь - разделить Telegram-бота и веб-приложение на разные процессы (запускать их отдельно).
Проблема в том, что вы пытаетесь запустить цикл обработчика телеграмм внутри приложения Djnago. Это не сработает по нескольким причинам:
- Django запускает более одного рабочего, а ваша библиотека бота Telegram, похоже, не поддерживает запуск параллельных рабочих.
- Django запускает код синхронно, и это означает, что даже если вам удастся запустить код Telegram-бота, это приведет к зависанию сервера веб-приложения из-за бесконечного цикла в обработчике Telegram-бота .
Более того, сейчас вы используете сервер Django Development с помощью команды manage.py
, но если вы собираетесь развернуть свое приложение в производственной среде, ваша конфигурация будет отличаться: вам следует использовать какое-нибудь готовое к производству решение, например gunicorn. Различные конфигурации веб-сервера в разных средах затруднят написание корректного и масштабируемого кода для обслуживания как веб-приложения, так и Telegram-бота.
Я понимаю, что вы, скорее всего, ищете способ получить данные из Django ORM внутри бота Telegram или использовать некоторые другие возможности Django. Если это так, то вы все еще можете получить доступ к django из других ваших скриптов. Все, что вам нужно сделать, это указать переменную окружения DJANGO_SETTINGS_MODULE
, чтобы помочь Django найти ваш модуль настроек.
Итак, создайте отдельный скрипт Python (например, telegram_bot.py
в корне вашего приложения) для запуска вашего Telegram-бота и запустите его отдельно.
$ DJANGO_SETTINGS_MODULE=yourapp.settings telegram_bot.py
запустит вашего бота, а вы сможете импортировать Django Models и работать с ними внутри этого скрипта.