Metadata-Version: 2.4
Name: django-utils2
Version: 4.1.2
Summary: Django Utils is a module with some convenient utilities not included with the standard Django install
Author: Rick van Hattem
Author-email: Rick van Hattem <Wolph@Wol.ph>
License-Expression: BSD-3-Clause
License-File: LICENSE
Classifier: Development Status :: 6 - Mature
Classifier: Environment :: Web Environment
Classifier: Framework :: Django
Classifier: Framework :: Django :: 4.2
Classifier: Framework :: Django :: 5.2
Classifier: Framework :: Django :: 6.0
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Natural Language :: English
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 :: Internet :: WWW/HTTP
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Dist: django>=4.2
Requires-Dist: python-utils>=3.5.2
Requires-Dist: cryptography>=42.0 ; extra == 'crypto'
Requires-Dist: django-utils2[tests] ; extra == 'dev'
Requires-Dist: ruff>=0.15.0 ; extra == 'dev'
Requires-Dist: mypy>=1.14 ; extra == 'dev'
Requires-Dist: django-stubs[compatible-mypy]>=5.1 ; extra == 'dev'
Requires-Dist: basedpyright>=1.0 ; extra == 'dev'
Requires-Dist: pyrefly>=0.1 ; extra == 'dev'
Requires-Dist: ty>=0.0.56 ; extra == 'dev'
Requires-Dist: sphinx>=8.0 ; extra == 'docs'
Requires-Dist: furo>=2025.1 ; extra == 'docs'
Requires-Dist: myst-parser>=4.0 ; extra == 'docs'
Requires-Dist: sphinx-design>=0.6 ; extra == 'docs'
Requires-Dist: sphinx-copybutton>=0.5 ; extra == 'docs'
Requires-Dist: django-utils2[crypto] ; extra == 'tests'
Requires-Dist: pytest>=8.0 ; extra == 'tests'
Requires-Dist: pytest-django>=4.8,<4.13 ; extra == 'tests'
Requires-Dist: pytest-cov>=6.0 ; extra == 'tests'
Requires-Dist: coverage>=7.0 ; extra == 'tests'
Requires-Dist: django-coverage-plugin>=3.1 ; extra == 'tests'
Requires-Dist: pygments>=2.0 ; extra == 'tests'
Requires-Dist: tox>=4.0 ; extra == 'tox'
Requires-Dist: tox-uv>=1.0 ; extra == 'tox'
Requires-Python: >=3.10
Project-URL: Homepage, https://github.com/WoLpH/django-utils
Project-URL: Documentation, https://django-utils-2.readthedocs.io/
Project-URL: Bug Tracker, https://github.com/WoLpH/django-utils/issues
Provides-Extra: crypto
Provides-Extra: dev
Provides-Extra: docs
Provides-Extra: tests
Provides-Extra: tox
Description-Content-Type: text/markdown

# Django Utils

[![CI](https://github.com/WoLpH/django-utils/actions/workflows/ci.yml/badge.svg)](https://github.com/WoLpH/django-utils/actions/workflows/ci.yml)
[![PyPI version](https://img.shields.io/pypi/v/django-utils2.svg)](https://pypi.org/project/django-utils2/)
[![Python versions](https://img.shields.io/pypi/pyversions/django-utils2.svg)](https://pypi.org/project/django-utils2/)
[![Documentation](https://readthedocs.org/projects/django-utils-2/badge/?version=latest)](https://django-utils-2.readthedocs.io/en/latest/)

![The data__filling dropdown filter open in the Django admin sidebar, listing Avocado, Bacon, Cheddar, Corned Beef and Turkey](https://raw.githubusercontent.com/WoLpH/django-utils/master/docs/_static/screenshots/filters-sidebar.png)

Django Utils is a collection of the small Django helpers, admin
power-ups and ORM utilities that most projects end up writing
themselves: JSON-aware admin filters, encrypted model fields,
memory-bounded queryset iteration, resumable management commands, and
more. It builds on the
[Python Utils](https://github.com/WoLpH/python-utils) library. It is
by no means a complete collection, but it has served production
projects well and keeps growing.

Full documentation, including a "why this over the alternatives" page, is
at <https://django-utils-2.readthedocs.io/en/latest/>.

## Requirements

- Python 3.10+
- Django 4.2, 5.2, or 6.0

## Install

1. Run `pip install django-utils2`
2. Add `django_utils` to your `INSTALLED_APPS`

If you want to run the tests, install the `tests` extra
(`pip install "django-utils2[tests]"`) and run `pytest`.

## Quickstart

Filter an admin changelist on a nested `JSONField` value without
writing a custom `SimpleListFilter`:

```python
from django.contrib import admin
from django_utils.admin.filters import JSONFieldFilterDropdown

from myapp.models import Sandwich


class SandwichAdmin(admin.ModelAdmin):
    list_filter = (
        JSONFieldFilterDropdown.create('data__filling'),
    )


admin.site.register(Sandwich, SandwichAdmin)
```

A sidebar filter on `data['filling']`, no JOIN or denormalized column.
The [quickstart](https://django-utils-2.readthedocs.io/en/latest/quickstart.html)
page has two more features like this.

## Features

Every feature below has its own page on the docs site, with runnable
examples, edge cases, and (for the admin features) screenshots or a live
in-browser demo.

- **Admin dropdown / Select2 / JSON filters**: dropdown, autocomplete, and
  JSON sub-path list filters for the changelist sidebar, plus an operator
  selector (`gte`, `lte`, `icontains`, ...) for typed comparisons. See
  [Select / dropdown / autocomplete filters](https://django-utils-2.readthedocs.io/en/latest/admin.html#dropdown-filters)
  and [Operator filters](https://django-utils-2.readthedocs.io/en/latest/admin.html#operator-filters).
- **JSON widget**: a drop-in `JSONField` admin widget that pretty-prints
  and validates JSON as you type. See
  [JSON widget](https://django-utils-2.readthedocs.io/en/latest/admin.html#json-widget-section).
- **Read-only admin**: turn any `ModelAdmin` into a read-only view:
  add/change/delete denied for everyone, filtering and search still work.
  See [Read-only admin](https://django-utils-2.readthedocs.io/en/latest/admin.html#read-only-admin).
- **Count columns**: sortable related-object count columns for
  `list_display`, without the N+1 or JOIN fan-out footguns. See
  [Count columns](https://django-utils-2.readthedocs.io/en/latest/admin.html#count-columns).
- **Admin export**: streaming CSV/JSON export actions for the changelist,
  memory-bounded via `queryset_iterator`. See
  [Export](https://django-utils-2.readthedocs.io/en/latest/admin.html#admin-export).
- **Choices**: metadata-carrying choices with dict-like access and a real
  `enum.Enum` on demand via `as_enum()`. See
  [Choices](https://django-utils-2.readthedocs.io/en/latest/models-fields.html#choices).
- **PostgreSQL ENUM field**: a `CharField` backed by a native PostgreSQL
  `ENUM` type on Postgres, plain `VARCHAR` everywhere else, with
  hand-written migration operations for creating the type and adding
  values. See
  [PostgreSQL ENUM field](https://django-utils-2.readthedocs.io/en/latest/models-fields.html#postgresql-enum-field).
- **Request/user context (ASGI-safe)**: access the current request/user
  from anywhere via `contextvars`, isolated per asyncio task, unlike
  thread-local equivalents. See
  [Current request / user (ASGI-safe)](https://django-utils-2.readthedocs.io/en/latest/middleware.html#current-request-user-asgi-safe).
- **Query budgets**: catch N+1 regressions in production code paths, not
  just in tests, with a query-counting context manager/decorator. See
  [Query budgets](https://django-utils-2.readthedocs.io/en/latest/middleware.html#query-budgets).
- **Auth helpers**: `superuser_required`/`staff_required` decorators and a
  `permission_string()` builder for `has_perm()` checks. See
  [Auth helpers](https://django-utils-2.readthedocs.io/en/latest/middleware.html#auth-helpers).
- **Fetch-Metadata CSRF middleware**: defense-in-depth CSRF hardening
  using the `Sec-Fetch-Site` header, run alongside (not instead of)
  Django's own CSRF middleware. See
  [Fetch-Metadata CSRF middleware](https://django-utils-2.readthedocs.io/en/latest/middleware.html#fetch-metadata-csrf-middleware).
- **Subquery aggregates**: `SubqueryCount`/`SubquerySum`/`SubqueryAvg`/...
  annotate each aggregate in its own subquery, avoiding the JOIN fan-out
  that multiplies counts. See
  [Subquery aggregates](https://django-utils-2.readthedocs.io/en/latest/querysets.html#subquery-aggregates).
- **Bulk upsert**: `bulk_update_or_create()`: one
  `INSERT ... ON CONFLICT DO UPDATE` batch instead of a racy,
  two-query-per-row loop. See
  [Bulk upsert](https://django-utils-2.readthedocs.io/en/latest/querysets.html#bulk-upsert).
- **Chunked management commands**: `ChunkedCommand`: memory-bounded,
  resumable processing of large querysets with progress logging and a
  transactional dry-run. See
  [ChunkedCommand](https://django-utils-2.readthedocs.io/en/latest/commands.html#chunkedcommand).
- **Encrypted model fields**: `EncryptedCharField`/`EncryptedTextField`/
  `EncryptedJSONField`: Fernet-encrypted values in a plain `TEXT` column,
  with key-rotation support. See
  [Encrypted model fields](https://django-utils-2.readthedocs.io/en/latest/models-fields.html#encrypted-model-fields).

## Links

- Documentation: <https://django-utils-2.readthedocs.io/en/latest/>
- Source: <https://github.com/WoLpH/django-utils>
- Bug reports: <https://github.com/WoLpH/django-utils/issues>
- Package homepage: <https://pypi.org/project/django-utils2/>
- My blog: <http://w.wol.ph/>
