Metadata-Version: 2.4
Name: django-sqllogging
Version: 1.0.1
Summary: Pretty, useful SQL logging for Django development
Author: Simon Percivall
Author-email: Simon Percivall <simon.percivall@prorenata.se>
License-Expression: BSD-3-Clause
License-File: LICENSE
Classifier: Development Status :: 5 - Production/Stable
Classifier: Framework :: Django
Classifier: Framework :: Django :: 5.2
Classifier: Framework :: Django :: 6.0
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Database
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Dist: django>=5.2
Requires-Dist: pygments>=2.0
Requires-Dist: termcolor>=2.3
Requires-Python: >=3.12
Project-URL: Homepage, https://github.com/simonpercivall/django-sqllogging
Project-URL: Repository, https://github.com/simonpercivall/django-sqllogging
Project-URL: Changelog, https://github.com/simonpercivall/django-sqllogging/blob/main/CHANGELOG.md
Project-URL: Issues, https://github.com/simonpercivall/django-sqllogging/issues
Description-Content-Type: text/markdown

# django-sqllogging

Pretty, useful SQL logging for Django development.

- Re-formats and syntax-highlights SQL queries in the terminal
- Color-codes mutation queries (INSERT, UPDATE, DELETE, ALTER); syntax-highlights SELECTs
- Logs queries **before** execution with inlined parameters
- Logs query duration with slow-query highlighting
- Shows the request path that triggered each query
- Shows stack traces to find where queries originate
- Detects implicitly loaded relations (forward FK, forward/reverse one-to-one)

## Installation

```bash
pip install django-sqllogging
```

## Quick Start

Add `django_sqllogging` to your installed apps:

```python
# settings.py
INSTALLED_APPS = [
    # ...
    "django_sqllogging",
]
```

Then control SQL logging via the `sqldebug` environment variable:

```bash
# Log all queries
sqldebug=query python manage.py runserver

# Log queries with stack traces
sqldebug=query,stack python manage.py runserver

# Log queries with the request path (requires middleware, see below)
sqldebug=query,request python manage.py runserver

# Log implicitly loaded relations
sqldebug=rels python manage.py runserver

# Everything
sqldebug=query,stack,rels,request python manage.py runserver
```

That's it — when `sqldebug` is set and no explicit logging configuration exists, a default handler is added automatically.

For custom logging setups (file output, different formatters, etc.), see [Advanced Configuration](#advanced-configuration).

### Example Output

With `sqldebug=query`:

```
[django_sqllogging] ===>
  SELECT id, name, email
  FROM myapp_user
  WHERE active = 1
  AND role = 'admin'
  ORDER BY created_at;
  SQL Time: 0.0023
```

With `sqldebug=rels`:

```
[django_sqllogging] ===> 'profile' implicitly fetched on 'User'
```

Mutation queries (INSERT, UPDATE, DELETE) are color-coded. Slow queries (>0.1s by default) show the duration in red. In `stack` mode, a filtered stack trace appears above each query showing the application code that triggered it.

### Shortcuts

| Value | Equivalent |
|-------|-----------|
| `1` or `t` | `query` |
| `2` | `query,stack` |
| `trace` | `stack` |
| `0` or `f` | disabled |

## Request Path Tracking

To display the request path that triggered each query, add the middleware early in the list — queries from middleware above it won't have request context:

```python
MIDDLEWARE = [
    "django_sqllogging.middleware.sql_logging_middleware",
    # ... other middleware
]
```

Then use `sqldebug=query,request` or `sqldebug=query,stack` (stack mode includes the request path automatically).

The middleware supports both WSGI and ASGI (sync and async Django).

### Third-party compatibility

If you already have **django-crum** or **django-threadlocals** middleware active in your `MIDDLEWARE`, the built-in middleware is unnecessary — `django-sqllogging` auto-detects these libraries and reads the current request from them. No configuration needed.

Without any middleware (built-in or third-party), request path display silently shows nothing.

## How It Works

When `django_sqllogging` is in `INSTALLED_APPS` and the logger is configured, the library patches Django's `CursorDebugWrapper` (used when `DEBUG = True`) to log queries before execution with inlined parameters. It also patches relation descriptors to detect implicit relation loading.

These patches are dormant when the `sqldebug` env var is not set — the overhead is negligible (one attribute check per query or relation access).

Request path tracking uses a lightweight `ContextVar`-based middleware (or auto-detects compatible third-party middleware) instead of walking the call stack.

## Advanced Configuration

### Using SqlFormatter with a different handler

`SqlFormatter` can be used independently with any handler (FileHandler, SysLogHandler, etc.):

```python
LOGGING = {
    "version": 1,
    "disable_existing_loggers": False,
    "formatters": {
        "sql": {
            "()": "django_sqllogging.SqlFormatter",
            "project_name": "myapp",
        },
    },
    "filters": {
        "sql_debug": {"()": "django_sqllogging.SqlDebugFilter"},
    },
    "handlers": {
        "sql_file": {
            "class": "logging.FileHandler",
            "filename": "sql.log",
            "formatter": "sql",
            "filters": ["sql_debug"],
        },
    },
    "loggers": {
        "django_sqllogging": {"level": "DEBUG", "handlers": ["sql_file"], "propagate": False},
    },
}
```

`SqlDebugFilter` suppresses records when the `sqldebug` env var is not set. Without it, all SQL records are written regardless of `sqldebug`.

### Overriding SQL_DEBUG programmatically

The `sqldebug` env var is auto-detected at startup. To override it in settings:

```python
SQL_DEBUG = {"query", "stack"}  # Always enable query + stack mode
```

If `SQL_DEBUG` is set explicitly in settings (even to `None`), the env var is ignored.

## Formatter Options

| Option | Default | Description |
|--------|---------|-------------|
| `project_name` | Last component of `BASE_DIR` | Controls how stack trace paths are shortened |
| `slow_threshold` | `0.1` (seconds) | Duration above this is highlighted red |
| `max_sql_length` | `10000` (chars) | SQL longer than this is truncated |

## Requirements

- Python 3.12+
- Django 5.2+ with `DEBUG = True` (pre-execution logging uses `CursorDebugWrapper`)

## See also

- **[nplusone](https://github.com/jmcarp/nplusone)** — N+1 query detection for Django
  and SQLAlchemy with middleware-based profiling, eager-load analysis, and test-mode
  exceptions. Unmaintained since 2020 but stable.

## License

BSD 3-Clause. See [LICENSE](LICENSE) for details.
