Metadata-Version: 2.5
Name: django-aiogram
Version: 4.1.0
Summary: Run aiogram next to Django and send Telegram messages from anywhere, over a Redis list, Redis Streams, RabbitMQ or Kafka
Project-URL: Homepage, https://github.com/CorneiZeR/django-aiogram
Project-URL: Documentation, https://corneizer.github.io/django-aiogram/
Project-URL: Changelog, https://github.com/CorneiZeR/django-aiogram/blob/master/CHANGELOG.md
Project-URL: Issues, https://github.com/CorneiZeR/django-aiogram/issues
Project-URL: Repository, https://github.com/CorneiZeR/django-aiogram
Project-URL: Funding, https://github.com/sponsors/CorneiZeR
Author-email: Oleksii Kolosiuk <kolosyuk1@gmail.com>
License-Expression: MIT
License-File: LICENSE
Keywords: aiogram,asyncio,bot,django,docker,kafka,message-queue,rabbitmq,redis,redis-streams,telegram
Classifier: Development Status :: 5 - Production/Stable
Classifier: Framework :: AsyncIO
Classifier: Framework :: Django
Classifier: Framework :: Django :: 5.2
Classifier: Framework :: Django :: 6.0
Classifier: Framework :: Django :: 6.1
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Communications :: Chat
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: <3.15,>=3.10
Requires-Dist: aiogram>=3.30
Requires-Dist: django>=5.2
Provides-Extra: hiredis
Requires-Dist: redis[hiredis]>=6.2; extra == 'hiredis'
Provides-Extra: kafka
Requires-Dist: confluent-kafka>=2.12.1; (python_version >= '3.14') and extra == 'kafka'
Requires-Dist: confluent-kafka>=2.6; (python_version < '3.14') and extra == 'kafka'
Provides-Extra: prometheus
Requires-Dist: prometheus-client>=0.20; extra == 'prometheus'
Provides-Extra: rabbitmq
Requires-Dist: pika>=1.3; extra == 'rabbitmq'
Provides-Extra: redis
Requires-Dist: redis>=6.2; extra == 'redis'
Description-Content-Type: text/markdown

# django-aiogram

[![PyPI](https://img.shields.io/pypi/v/django-aiogram.svg)](https://pypi.org/project/django-aiogram/)
[![Python](https://img.shields.io/pypi/pyversions/django-aiogram.svg)](https://pypi.org/project/django-aiogram/)
[![CI](https://github.com/CorneiZeR/django-aiogram/actions/workflows/ci.yml/badge.svg)](https://github.com/CorneiZeR/django-aiogram/actions/workflows/ci.yml)
[![License](https://img.shields.io/pypi/l/django-aiogram.svg)](https://github.com/CorneiZeR/django-aiogram/blob/master/LICENSE)

Run [aiogram](https://docs.aiogram.dev/) next to Django: write handlers as
ordinary Django app code, and send Telegram messages from anywhere in the
project.

One container runs the bot. Every other process — web, Celery, a management
command — hands the call to a broker and returns, so a request never waits on
Telegram. **Four transports can carry it**, and `BROKER` says which:

```text
                              ┌─ Redis list ────┐
  web, celery ──bot.send()──▶ ├─ Redis Streams ─┤ ──▶ start_tgbot ──▶ Telegram
                              ├─ RabbitMQ ──────┤
                              └─ Kafka ─────────┘
```

| transport | `BROKER` | extra | its own required settings |
| --- | --- | --- | --- |
| Redis list *(default)* | `django_aiogram.broker.redis_list.RedisListBroker` | `[redis]` | — |
| Redis Streams | `django_aiogram.broker.redis_streams.RedisStreamsBroker` | `[redis]` | `REDIS_STREAM_KEY` |
| RabbitMQ | `django_aiogram.broker.rabbitmq.RabbitMQBroker` | `[rabbitmq]` | `RABBITMQ_URL`, `RABBITMQ_QUEUE` |
| Kafka | `django_aiogram.broker.kafka.KafkaBroker` | `[kafka]` | `KAFKA_BOOTSTRAP`, `KAFKA_TOPIC` |

Your code does not change with the row: the same `bot.send()`, handlers, event log and
`manage.py start_tgbot`. What differs is what becomes of a message whose worker was
killed mid-send, and what recovery is — a command, a clock, or the broker's own doing.
[Delivery](https://corneizer.github.io/django-aiogram/latest/Delivery/) compares them;
each transport has a page of its own below.

## Install

```shell
pip install 'django-aiogram[redis]'                 # Redis list, the default, or Redis Streams
pip install 'django-aiogram[rabbitmq,redis]'        # RabbitMQ
pip install 'django-aiogram[kafka,redis]'           # Kafka
```

One extra per transport, so a deployment downloads only the queue driver it uses.
**`redis` is in the other two lines for the FSM store, not the queue**: `FSM_STORAGE`
defaults to aiogram's Redis store, so a bot keeping chat state needs that driver whichever
transport carries its messages, and `FSM_STORAGE: 'memory'` is what drops it.

Nothing is inferred from what happens to be installed: `BROKER` names the transport, and a
base `pip install django-aiogram` imports and runs `manage.py` but carries no message.
`manage.py check` names every extra that is missing, with the `pip install` line;
[Installation](https://corneizer.github.io/django-aiogram/latest/Installation/) has the
exceptions.

```python
# settings.py
import os

INSTALLED_APPS = [..., 'django_aiogram']

TELEGRAM_BOT = {
    'TOKEN': os.environ.get('TELEGRAM_BOT_TOKEN', ''),
    # unset, BROKER resolves to RedisListBroker; the table above has the other three,
    # and each transport reads its own settings on top of these two
    'REDIS_URL': os.environ.get('REDIS_URL', ''),
}
```

Both may be empty: nothing connects or validates credentials at import time, so tests and
migrations run without them. Requires Python 3.10–3.14, Django 5.2+ and aiogram 3.30+; each
transport then pins its own driver and asks for its own server —
[Installation](https://corneizer.github.io/django-aiogram/latest/Installation/) has both, per row.

## Use it

```python
# myapp/tg_router.py — imported automatically from every installed app
from aiogram import F, types

from django_aiogram import bot


@bot.message(F.text == '/start')
async def start(message: types.Message) -> None:
    await message.answer('hi')
```

```python
# anywhere else in the project
from django_aiogram import bot

bot.send(chat_id=CHAT_ID, text='Order approved')
```

```shell
python manage.py start_tgbot
```

A router module, a call, and one process running the bot. That process gets Django's
between-requests connection handling without having any requests — every update is bracketed
with `close_old_connections()`, so a database that restarts under a long-running bot does not
leave every handler raising `InterfaceError` until somebody notices. Nothing to configure;
[Deployment](https://corneizer.github.io/django-aiogram/latest/Deployment/) says what the
healthcheck can and cannot see about it.

Everything else — rate limits, per-process opt-out, healthchecks — is configuration, documented
rather than required. Webhook mode is the one alternative that also asks for a URL route:
[Webhook](https://corneizer.github.io/django-aiogram/latest/Webhook/) has the four steps.

## Documentation

The [documentation site](https://corneizer.github.io/django-aiogram/) is the
documentation. Pages live in [`docs/wiki/`](https://github.com/CorneiZeR/django-aiogram/tree/master/docs/wiki), so they are reviewed in
the same pull request as the code they describe and published from `master`.

| | |
| --- | --- |
| [Installation](https://corneizer.github.io/django-aiogram/latest/Installation/) | install, configure, run |
| [Settings](https://corneizer.github.io/django-aiogram/latest/Settings/) | every setting, with defaults and check ids |
| [Handlers](https://corneizer.github.io/django-aiogram/latest/Handlers/) | routers, filters, FSM, the async ORM |
| [Sending messages](https://corneizer.github.io/django-aiogram/latest/Sending-messages/) | routes, keyboards, files, errors |
| [Testing](https://corneizer.github.io/django-aiogram/latest/Testing/) | your suite without a broker, asserting what was queued |
| [API](https://corneizer.github.io/django-aiogram/latest/API/) | the instance, its internals, and what stays public |
| [Delivery](https://corneizer.github.io/django-aiogram/latest/Delivery/) | how queued messages reach Telegram |
| [Redis list](https://corneizer.github.io/django-aiogram/latest/Redis-list/) | the default transport: what it guarantees, and why the worker's name matters |
| [Redis Streams](https://corneizer.github.io/django-aiogram/latest/Redis-Streams/) | the same server, a consumer group, and no worker identity to keep |
| [RabbitMQ](https://corneizer.github.io/django-aiogram/latest/RabbitMQ/) | a broker that tracks its own consumers, and one thread per connection |
| [Kafka](https://corneizer.github.io/django-aiogram/latest/Kafka/) | offsets settle a prefix, ordering is per partition, a refusal rewinds |
| [Webhook](https://corneizer.github.io/django-aiogram/latest/Webhook/) | receiving updates over HTTP instead of polling |
| [Rate limits](https://corneizer.github.io/django-aiogram/latest/Rate-limits/) | staying inside Telegram's published limits |
| [Deployment](https://corneizer.github.io/django-aiogram/latest/Deployment/) | compose recipes, healthchecks, per-process opt-out |
| [Logging](https://corneizer.github.io/django-aiogram/latest/Logging/) | the logger and its structured fields |
| [Event log](https://corneizer.github.io/django-aiogram/latest/Event-log/) | recording what the bot did to a table, and a signal to count it without one |
| [Serialization](https://corneizer.github.io/django-aiogram/latest/Serialization/) | what can be queued |
| [Troubleshooting](https://corneizer.github.io/django-aiogram/latest/Troubleshooting/) | symptoms and their usual causes |
| [Upgrading](https://corneizer.github.io/django-aiogram/latest/Upgrading/) | what each major release changed, and what you must do |
| [AI assistants](https://corneizer.github.io/django-aiogram/latest/AI-assistants/) | the brief to hand a coding agent |

Upgrading from 3.x: the distribution is `django-aiogram` and the import path is
`django_aiogram`, the driver is an extra you now name, and the event log has a table of its
own. The upgrading page walks it in order, `migrate` included.

## Contributing

[CONTRIBUTING.md](https://github.com/CorneiZeR/django-aiogram/blob/master/CONTRIBUTING.md) for the workflow, [AGENTS.md](https://github.com/CorneiZeR/django-aiogram/blob/master/AGENTS.md) for
the same ground in the form coding agents read. Changes are in
[CHANGELOG.md](https://github.com/CorneiZeR/django-aiogram/blob/master/CHANGELOG.md); security reports go through
[SECURITY.md](https://github.com/CorneiZeR/django-aiogram/blob/master/SECURITY.md).
