Build your Telegram bots in a Django way.
Decorator routing · Messages and keyboards in the admin · Fully typed
Documentation · Getting started · Examples · Migration guide
demo.mp4
The fastest way to build a production-ready Telegram bot on Django. You write plain functions, decorate them with a trigger, and the library does the routing. Your texts and keyboards live in the database, so you can change them from the admin without a redeploy.
from dj_telegram_bot.core.guards import staff_required
from dj_telegram_bot.core.handlers import callback_handler, command_handler
@command_handler("start")
def start(ctx):
ctx.bot.send_message(ctx.chat_id, "Hello!")
@callback_handler("buy_*")
def buy(ctx):
item = ctx.callback_data.removeprefix("buy_")
ctx.bot.answer_callback_query(ctx.callback_query.id, text=f"Added {item}")
@command_handler("stats")
@staff_required
def stats(ctx):
ctx.bot.send_message(ctx.chat_id, "Staff only!")| 🧭 Decorator routing | @command_handler, @message_handler, @callback_handler, @inline_handler, @chosen_handler, plus step handlers and * wildcards |
| 🧩 Function or class handlers | Use whichever style you like. Classes inherit from UpdateHandler, and everything is imported from dj_telegram_bot.core.handlers |
| ⌨️ Edit from the admin | Build messages and keyboards visually in the Django admin. No redeploy |
| 🛡️ Built-in guards | @sponsor_required, @staff_required, @superuser_required, and @before_handler for your own checks |
| 👤 Optional user model | Let the bot create users, bring your own model, or use none at all |
| 🔒 Fully typed | The whole Telegram Bot API is modeled with Pydantic, with autocomplete everywhere |
| 🛠️ Maintenance mode | Pause the bot and show a custom message, from the admin or from code |
| 🌐 Proxy and local server | SOCKS5 proxy and local Bot API server (TDLib) support |
pip install dj_telegram_botor with uv:
uv add dj_telegram_botUpgrading from 0.1.x? Read the Migration guide.
1. Settings
# settings.py
INSTALLED_APPS = [..., "dj_telegram_bot.contrib"]
BOT_TOKEN = "your-telegram-bot-token"
TM_WEBHOOK_URL = "https://api.telegram.org" # or your local Bot API server2. URLs and migrations
# urls.py
urlpatterns = [..., path("telegram/", include("dj_telegram_bot.contrib.urls"))]python manage.py migrate3. Set the webhook (once)
curl "https://api.telegram.org/bot<BOT_TOKEN>/setWebhook?url=https://yourdomain.com/telegram/webhook/"4. Write your first handler
# your_app/bot_handlers/start.py (auto-discovered)
from dj_telegram_bot.core.handlers import command_handler
@command_handler("start")
def start(ctx):
ctx.bot.send_message(ctx.chat_id, "Hello!")Open your bot in Telegram and send /start. It answers Hello! 🎉
Telegram ──webhook──▶ Dispatcher ──▶ before handlers ──▶ Router ──▶ your function
Every update is wrapped in a handler object, passes through your @before_handler checks, and the router picks the first match: exact trigger, then the user's step, then wildcards.
| I want to... | Read |
|---|---|
| reply to commands, messages and buttons | Handlers |
| copy a working example | Examples |
| build a conversation | Steps and User model |
| limit a command or require joining a channel | Access control |
| block users or pause the bot | Before handlers |
| edit texts and keyboards without redeploying | Messages & keyboards |
| upgrade from 0.1.x | Migration guide |
Full guide: https://zankoan.github.io/dj_telegram_bot/
Contributions are welcome! Found a bug, have an idea, or spotted a typo in the docs? Open an issue or send a pull request.
Please keep pull requests small and focused