This release is a pre-release and may not be stable for production use.
django-signals-all
Release candidate.
django-signals-allest en1.0.0rc1: l'API est considérée figée mais n'a pas encore été éprouvée par un usage réel en dehors de ce dépôt. Les retours (issues, cas d'usage, bugs) sont les bienvenus avant de tagger la version1.0.0finale — voir RELEASING.md.
Des signaux Django garantis, peu importe comment vous modifiez vos données.
Le problème
Les opérations en masse (bulk_create, bulk_update, QuerySet.update()) et le SQL
brut (cursor.execute()) exécutent du SQL direct. Elles contournent Model.save() et
ne déclenchent aucun signal Django, ce qui casse l'invalidation de cache, la
réindexation de recherche et la traçabilité des audit logs.
django_signals_all fournit deux niveaux de capture :
- ORM (
django_signals_all.orm) — unQuerySet/Managerpersonnalisé qui émet des signaux applicatifs pourupdate(),bulk_create()etbulk_update(). - SQL brut (
django_signals_all.sql) — un middleware basé surconnection.execute_wrapperqui analyse le SQL exécuté via un curseur et émet un signal sur lesINSERT/UPDATE/DELETE.
Un troisième module, pg_notify (triggers PostgreSQL LISTEN/NOTIFY pour capturer
les mutations effectuées hors de l'application Django), est prévu en roadmap et n'est
pas encore implémenté.
Installation
uv add django-signals-all
# settings.py
INSTALLED_APPS = [
...,
"django_signals_all",
]
MIDDLEWARE = [
...,
"django_signals_all.sql.middleware.RawSQLSignalMiddleware",
]
Module ORM
Le modèle doit utiliser BulkSignalManager comme manager :
# models.py
from django.db import models
from django_signals_all.orm.manager import BulkSignalManager
class Article(models.Model):
title = models.CharField(max_length=200)
status = models.CharField(max_length=20, default="draft")
objects = BulkSignalManager()
# receivers.py
from django.dispatch import receiver
from django.core.cache import cache
from django_signals_all.signals import post_bulk_update, post_bulk_create
from .models import Article
@receiver(post_bulk_update, sender=Article)
def invalidate_cache_on_bulk_update(sender, updated_ids, update_kwargs, using, **kwargs):
"""Déclenché même par Article.objects.filter(...).update(...)."""
cache.delete_many([f"article:{pk}" for pk in updated_ids])
@receiver(post_bulk_create, sender=Article)
def index_on_bulk_create(sender, objects, using, **kwargs):
"""Déclenché après Article.objects.bulk_create([...])."""
search_engine.index_many(objects)
Manager.bulk_update() découpe ses mises à jour en plusieurs requêtes SQL internes
(batch_size) ; ces requêtes internes n'émettent pas post_bulk_update — seul un
post_bulk_model_update unique et agrégé est envoyé, avec l'ensemble des instances et
des champs modifiés :
from django_signals_all.signals import post_bulk_model_update
@receiver(post_bulk_model_update, sender=Order)
def track_bulk_status_change(sender, updated_instances, fields_updated, using, **kwargs):
if "status" in fields_updated:
for order in updated_instances:
audit_log.record(order)
Tous les signaux ORM sont envoyés via transaction.on_commit() : ils ne sont jamais
émis pour une mutation finalement annulée par un rollback.
Module SQL brut
Le signal raw_sql_executed utilise le nom de la table comme sender, pas comme
un kwarg de filtrage arbitraire (@receiver(signal, table_name=...) n'est pas une API
Django valide — receiver()/Signal.connect() ne filtrent que sur sender) :
import logging
from django.dispatch import receiver
from django_signals_all.signals import raw_sql_executed
logger = logging.getLogger("security")
@receiver(raw_sql_executed, sender="crm_client")
def audit_raw_sql_on_crm_client(sender, operation, sql, params, using, **kwargs):
if operation in ("UPDATE", "DELETE"):
logger.warning("Mutation SQL brute (%s) sur %s : %s", operation, sender, sql)
Configuration
# settings.py
DJANGO_SIGNALS_ALL = {
# Module ORM : récupérer les PK impactées avant un update() en masse.
"FETCH_UPDATED_IDS": True,
"MAX_FETCH_IDS_LIMIT": 10_000,
# Module SQL brut.
"ENABLE_RAW_SQL_INTERCEPTOR": True,
"MONITORED_TABLES": None, # ou une liste blanche, ex. ["users_user", "crm_client"]
"EXCLUDED_TABLES": ["django_session", "django_migrations"],
"SQL_PARSER_ENGINE": "sqlglot", # ou "regex"
}
Si aucun receiver n'est connecté à un signal, la bibliothèque évite le travail supplémentaire correspondant (pas de requête pour récupérer les IDs, pas de parsing SQL).
Limitations connues
- Le moteur
regexne comprend pas les CTE (WITH ... UPDATE ...) : il ne détecte pas la table cible dans ce cas. Utilisez le moteursqlglot(par défaut) si votre application en dépend. - Le parsing SQL est du best-effort : une requête que le moteur configuré ne sait pas
analyser est ignorée silencieusement (avec un log de niveau
warningpoursqlglot), jamais une exception propagée à l'application. - Le module
pg_notifyn'existe pas encore dans cette version.
Développement
uv sync --group dev
uv run ruff check src tests
uv run ruff format --check src tests
uv run mypy
# SQLite (par défaut, pas de dépendance externe)
uv run pytest --cov=django_signals_all --cov-report=term-missing
# PostgreSQL et MySQL (nécessite Docker)
docker compose up -d
DSA_TEST_DB=postgres uv run pytest
DSA_TEST_DB=mysql uv run pytest
La CI (.github/workflows/ci.yml) exécute lint, typecheck (mypy strict) et la suite
complète sur les trois SGBD à chaque push.
Voir CONTRIBUTING.md pour contribuer, CHANGELOG.md pour l'historique des versions, et RELEASING.md pour le process de publication.
Licence
Metadata
Release files for django-signals-all 1.0.0rc2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| django_signals_all-1.0.0rc2.tar.gz | 71.4 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| django_signals_all-1.0.0rc2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 83.7 kB
Release files / django_signals_all-1.0.0rc2.tar.gz
| Download URL | django_signals_all-1.0.0rc2.tar.gz |
|---|---|
| Size | 71.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
297191d233543aec7d80ff735b476a095cc59828242f7c0e0931ccf1d6fa10ec
|
|
BLAKE2b-256 checksum How to use checksums |
cce64dc4498f8dc7d565edc6da81b49c45f0b63c7e1e29d96ac43c1cad3951a3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 13, 2026.
Transparency logRelease files / django_signals_all-1.0.0rc2-py3-none-any.whl
| Download URL | django_signals_all-1.0.0rc2-py3-none-any.whl |
|---|---|
| Size | 12.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
50c7d4be32482ab0a54bb425fec9514e59922da9fa63b5ff00399ef5fb970a6d
|
|
BLAKE2b-256 checksum How to use checksums |
0e8eb151e5ca23a4ac495e8cbc1a44714dd93238b8b199bd95c8149c610c32c4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 13, 2026.
Transparency logSecurity for django-signals-all 1.0.0rc2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for django_signals_all-1.0.0rc2.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 13, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.