django-adminactions and the admin operations Django does not ship
collection of useful django actions to use with ModelAdmin or AdminSite.
At a glance
- What is it?
- django-adminactions is a collection of admin actions for Django's ModelAdmin and AdminSite, covering exports, mass updates, record merging, duplicate finding and a queryset graph. It fits a team that treats the admin as an operational tool rather than a demo, and it is the wrong choice for a project whose admins are read only.
- Who is it for?
- django-adminactions fits a Django project whose admin users perform real data work, where exporting a filtered queryset, merging duplicate records or updating rows in bulk is a weekly task rather than an exception. It is the wrong choice for a project that already has a custom data pipeline or a dedicated admin package, and the wrong choice if you need audited bulk mutations, since the documentation does not describe any audit trail.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 158 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Nine admin actions, all of them things you would otherwise write yourself
django-adminactions is a collection of useful actions to use with `django.contrib.admin.ModelAdmin` and/or `django.contrib.admin.AdminSite`, and the action list is short enough to read in one glance.
Export as CSV, export as Excel, export as fixture, export delete tree, mass update records, graph queryset, merge records, find duplicates, and bulk update.
That list tells you what the package is for. Django's built in admin gives you the change list, the filters, the search and the delete action. Everything on this list is something a project with real data ends up writing as a one-off management command, or worse, as a sequence of manual steps through the admin interface. Exporting a filtered queryset to a spreadsheet is the classic example, and doing it by hand through the admin means selecting the rows, exporting, and reconciling the format.
Two of the entries are worth a second look because they are not exports. Merge records and find duplicates operate on the relationships between rows, which is the kind of operation that a hand rolled script gets wrong and that a data team is nervous about doing by hand.
The package is a Python project with a proper structure around it. The top level has a `src/` directory for the code, a `tests/` directory, a `docs/` directory, a `pyproject.toml`, a `tox.ini`, a `uv.lock`, a `Makefile`, a `manage.py` and a `mkdocs.yml` for the documentation build, plus a `.pre-commit-config.yaml` and a `CHANGES` file. The project metadata names Stefano Apostolico as both author and maintainer, and the homepage is a documentation site built with MkDocs.
The action and fixture exports are the two most immediately useful
Among the nine, the export family is the part that changes a team's working day, and the three variants cover three different destinations.
The CSV export is the obvious one and the one most people adopt the package for. The Excel export exists because a CSV is a poor deliverable for a non technical colleague, and the package pulls in `xlrd` and `xlwt` to produce a real spreadsheet file rather than a renamed CSV.
The fixture export is the more interesting one. Django's fixture format is the serialised form the framework itself uses for `dumpdata` and `loaddata`, so a fixture export is not a spreadsheet of a queryset, it is a set of model instances in a format the ORM can load back. For a project whose data is managed through Django, that means the export can be reloaded, diffed, or version controlled, which a CSV cannot.
Export delete tree is the fourth member of the family and it is a different shape again. The name implies it follows a relationship tree and exports or removes the whole thing, and a delete tree operation in an admin is a good example of something you want available and would rather not implement yourself.
Taken together, the export actions are a coherent group rather than a random list, and they are the part of this package that most clearly pays for itself on day one.
The mutation actions are where an admin gets dangerous
Mass update records, bulk update, merge records and find duplicates all change or reorganise data, and they are where the design questions live.
Mass update records and bulk update are two entries that sound close, and the documentation does not explain the difference between them. A Django admin action operates on the selected queryset, so what varies between them is likely the selection semantics rather than the mechanism, but that is an inference rather than something the documentation states, and it is the kind of detail you would want to read the source for.
Merge records is the most consequential of the set. Merging two records means choosing which values survive, and any implementation has to make a decision about conflicts. A merge that silently drops one side's field values is a data loss bug that looks like a feature.
Find duplicates is the safest of the mutation group in one sense, since identifying duplicates does not change anything, and it is the useful first step before merging them. The pairing of find and merge in the list suggests they are meant to be used together.
What none of these actions offers, based on what the documentation describes, is an audit trail. A mass update applied to a queryset of ten thousand rows through the admin is a significant event in the life of that data, and the package does not document any record of who ran it, when, or what the before and after values were. That is a real gap for a production system with data that matters, and it is worth checking in the source before you hand these actions to a team of administrators.
Graph queryset, which is the one that sounds like a toy and might not be
Graph queryset is the entry in the list that does not fit the pattern of the others, and it is worth spending a paragraph on because the name gives no clue.
The other eight actions are recognisable admin operations. Graph queryset is not a standard Django admin concept at all, and the visible documentation says nothing about what it produces. The name suggests producing a graph representation of a queryset, and given the package's other capabilities, a plausible reading is that it renders the relationships between the selected records as a graph rather than as rows.
That reading is a guess. The visible documentation does not describe the output format, whether it produces an image or a file, or what it is meant to be used for, and there is no screenshot of it in the visible readme the way there is for the export actions. It is the one feature here that a potential user cannot evaluate from the documentation, and the readme's own list is all that is offered.
The same applies in a different way to export delete tree, which is named but not explained at all. Both entries point to a documentation site as the place to find out more, and the visible repository does not fill the gap.
It is worth noting that the readme's project links point to a documentation site hosted at saxix.github.io, and that the repository has a `docs/` directory and a `mkdocs.yml` with a docs workflow badge, so the fuller documentation does exist somewhere. It is just not in the part that is visible here.
Building it locally, and the demo project the Makefile wires up
The Makefile in the repository shows the development workflow, and the `develop` target is the install step for a local checkout:
develop:
CRYPTOGRAPHY_DONT_BUILD_RUST=1 pip install -e .[dev,docs]The `CRYPTOGRAPHY_DONT_BUILD_RUST=1` part is there for a reason worth knowing, since it will not be obvious from the flag name alone. It suppresses the Rust build that a cryptography dependency would otherwise trigger during install, which is the difference between a development install that completes and one that compiles a native extension.
The `demo` target is the more interesting one, because it shows the whole thing running end to end. It migrates a demo settings module, loads fixture data, and starts the server:
demo:
PYTHONPATH=${PWD}:${PWD}/tests:${PWD}/src django-admin.py migrate --settings=demo.settings --noinput
PYTHONPATH=${PWD}:${PWD}/tests:${PWD}/src django-admin.py loaddata adminactions.json demoproject.json --settings=demo.settings
PYTHONPATH=${PWD}:${PWD}/tests:${PWD}/src django-admin.py runserver --settings=demo.settingsThe `PYTHONPATH` prefix, which points at the project root, the tests directory and the `src` directory, is there because the package lives under `src/` and the demo project needs to import it before it is installed.
The other targets are conventional. `lint` runs `pre-commit run --all`, `coverage` runs pytest with doctests and an HTML coverage report, `clean` removes build artifacts and compiled translation files, and `fullclean` also drops the MySQL and PostgreSQL databases named `adminactions` and `test_adminactions`.
The `docs` target is a slight oddity, since it runs `sphinx-build` while the project metadata and the `mkdocs.yml` at the root point at MkDocs. The `docs` directory exists in the tree and there is a separate documentation workflow badge. It is likely that the Sphinx path is a leftover, but the visible documentation does not say so explicitly, so treat the documentation build as something to check rather than assume.
A custom licence and a version line that has not moved much
Two things about the packaging are worth checking before you adopt the package.
The first is the licence. The repository records a custom licence that GitHub cannot classify, and the packaging metadata points at a `LICENSE` file with `license.file = "LICENSE"` rather than naming a standard SPDX identifier. By contrast, most Django ecosystem packages ship under the BSD or MIT licence, and the project metadata here does not name one. The `LICENSE` file is the authoritative source, and it is the document to read if the licence matters to your organisation. The top level also carries an `AUTHORS.md` and a `CHANGES` file.
The second is version movement. The recent releases are 2.4rc1 on 2025-02-27 and 2.4 on 2025-04-03, and the last push to the `develop` branch was on 2026-05-19. So the code is being worked on, and the newest release is from over a year earlier.
That is the shape of a package where the development happens on the default branch and the releases come less often. It is not a problem in itself, but it means pinning to the last release and tracking `develop` are two different experiences, and the documentation you read may be ahead of the version you install.
The dependency and version picture is otherwise healthy. The build backend is Hatchling with `hatch-vcs` for version handling, and the version is declared dynamic, so it comes from the repository tags rather than being written by hand. Python 3.10 or newer is required, and the Django classifiers cover 3.2, 4.2 and 5.1, which tells you the supported range of the framework without having to guess. The runtime dependencies are `django-stubs-ext`, `pytz`, `xlrd` and `xlwt`, so the Excel export is the only part of the package with a heavyweight dependency footprint.
The development tooling is broad and includes pytest-django, mypy, ruff, tox with a GitHub Actions plugin, and selenium, which suggests browser level tests exist for the admin pages.
Editorial conclusion
django-adminactions fits a Django project whose admin users perform real data work, where exporting a filtered queryset, merging duplicate records or updating rows in bulk is a weekly task rather than an exception. It is the wrong choice for a project that already has a custom data pipeline or a dedicated admin package, and the wrong choice if you need audited bulk mutations, since the documentation does not describe any audit trail. Before adopting, verify three things: the Django versions your project runs, because the classifiers cover 3.2, 4.2 and 5.1, that the Excel export dependency `xlrd` and `xlwt` are acceptable in your environment, and that the licence file matches your distribution requirements, since the package uses a custom licence rather than a standard one. The repository records a custom licence rather than a standard SPDX identifier, and the LICENSE file is the document to read, the last push was on 2026-05-19, and the newest release is 2.4 from 2025-04-03.
Frequently asked questions
What does django-adminactions add to the Django admin?
It provides a collection of actions usable with `django.contrib.admin.ModelAdmin` and/or `django.contrib.admin.AdminSite`, including export as CSV, export as Excel, export as fixture, export delete tree, mass update records, graph queryset, merge records, find duplicates and bulk update.
How do I install django-adminactions?
The package is on PyPI as `django-adminactions`, and for a local checkout the Makefile's `develop` target installs it in editable mode with `CRYPTOGRAPHY_DONT_BUILD_RUST=1 pip install -e .[dev,docs]`, where the environment variable avoids the Rust build that a cryptography dependency would otherwise trigger.
Which Django and Python versions does django-adminactions support?
The package requires Python 3.10 or newer, with classifiers for Python 3.10 through 3.13, and it declares support for Django 3.2, 4.2 and 5.1. The build backend is Hatchling with `hatch-vcs`, so the version is derived from the repository tags.
What are the runtime dependencies of django-adminactions?
The runtime dependencies are `django-stubs-ext`, `pytz`, `xlrd` and `xlwt`. The `xlrd` and `xlwt` pair is what backs the Excel export, and the development group adds pytest-django, mypy, ruff, tox, selenium and other tooling.
How do I run the django-adminactions demo project?
The Makefile provides a `demo` target that sets `PYTHONPATH` to the project root, the tests directory and `src`, then runs `django-admin.py migrate`, loads the `adminactions.json` and `demoproject.json` fixtures, and starts `runserver`, all against `demo.settings`.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/saxix-django-adminactions)Was this useful?