Запуск 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. Это не сработает по нескольким причинам:

  1. Django запускает более одного рабочего, а ваша библиотека бота Telegram, похоже, не поддерживает запуск параллельных рабочих.
  2. Django запускает код синхронно, и это означает, что даже если вам удастся запустить код Telegram-бота, это приведет к зависанию сервера веб-приложения из-за бесконечного цикла в обработчике Telegram-бота
  3. .

Более того, сейчас вы используете сервер 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 и работать с ними внутри этого скрипта.

Вернуться на верх