Minchin.Django.Excel
This is a Django app designed to allow you to push the contents of Excel workbooks to your Django database. I packaged it because while it seems like it should be simple, it involved many more moving pieces (including management commands, templates, template tags, admin pagination, etc.) than I initially thought it should.
Installation
The package is installable via pip:
pip install minchin.django.excel
This will also install all the required dependencies (of which there are many...).
From there, you need to add it to your list of installed apps in your Django
settings.py:
# settings.py
INSTALLED_APPS = [
# first in line
"related_admin", # for minchin.django.excel
# others...
"minchin.django.excel",
"prettyjson", # for minchin.django.excel
]
# other settings...
Second, ensure that your TEMPLATES setting contains a DjangoTemplates backend
whose APP_DIRS options is set to True:
# settings.py
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"APP_DIRS": True,
# ...
}
]
# other settings...
and then run the included database migrations:
python manage.py migrate
Loading Excel Data
Included is a Django management command to load the Excel files:
python manage.py load_excel <excel_file.xlsx> [<excel_file.xlsx> ...]
File names can include wildcards (e.g. reports/*.xlsx). Each file is stored
as a Workbook, with one Sheet per tab, and one Row per row. Each row's
data is stored as JSON, keyed by the Excel column name ({"A": ..., "B":
...}); empty cells are stored as null.
If the file is already in the database (matched by its MD5 hash), or a different file with the same name is, you'll be asked whether to replace it. To answer ahead of time:
--skip-existing(-s): don't reload files already in the database, and keep existing workbooks with the same name alongside the new one.--replace-existing(-r): replace existing workbooks, whether matched by hash or by name.
Each file is loaded in a single transaction, so a file that can't be read doesn't leave anything behind (or delete the workbook it was replacing).
From there, you would likely process the data further within Django.
Django Admin Site
There are also several helpers so that you can see the loaded data on the built-in Django admin site. However, you'll need to register them to your admin site:
# admin.py
from django.contrib import admin
from minchin.django.excel.admin import WorkbookAdmin, SheetAdmin, RowAdmin
from minchin.django.excel.models import Workbook, Sheet, Row
admin.site.register(Workbook, WorkbookAdmin)
admin.site.register(Sheet, SheetAdmin)
admin.site.register(Row, RowAdmin)
The Sheet page shows its rows in a paginated inline, RowInline. That's built
on minchin.django.excel.utils.PaginationInline, a TabularInline you can use
for your own models too:
per_page(default 20) rows are shown per page, andmax_show_all(default 200) is the most that the "Show all" link will show at once.- The page is set by the
<prefix>-pquery parameter (e.g.?row_set-p=3), so several paginated inlines on one page are paged independently. - The inline (or its model) needs an
ordering, so rows don't move between pages; otherwiseImproperlyConfiguredis raised.
License
The code is licensed under the MIT license. See attached License.txt
Changelog
Version 1.1.0 -- Oct. 5, 2026
In particular, this release is to keep this working (without errors) in Django 5.2 (and newer).
- remove legacy
jasonize-rowsmanagement command - fix the Sheet admin page crashing on Django 5.0+, and rework the paginated
inline: 1-based pages, a page parameter per inline (
<prefix>-p), elided page links, a limit on "Show all" (max_show_all), and its CSS is now loaded as a static file - breaking: remove the
back_url,forward_url, andmake_rangetemplate tags (fromexcel_tags), replaced byinline_pagination django.contrib.humanizeis no longer requiredload_excel: the same-filename prompt now respects--skip-existingand--replace-existing; files are loaded in a single transaction; rows are inserted in bulk; warn when a file pattern matches nothingfrom_timestamp: integer timestamps are now read as UTC (they were read in local time); unparseable strings raiseValueError; aware strings work- the JSON encoder handles numpy booleans
- require Django 4.2 or newer; drop the unused
psycopg2andpytzdependencies - fix the readme and license filenames in the package metadata
- add tests
Version 1.0.0 -- Dec. 12, 2025
- initial public release
Contributions
Contributions are welcome, however the scope of the project is intentionally limited.
To set up a development environment and run the tests:
pip install -e .[dev]
invoke load-tests
Code is formatted with isort and black.
Metadata
Release files for minchin.django.excel 1.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| minchin_django_excel-1.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Release files / minchin_django_excel-1.1.0-py3-none-any.whl
| Download URL | minchin_django_excel-1.1.0-py3-none-any.whl |
|---|---|
| Size | 24.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a9f034a558c31ffd0d85e38f6b342fadee98abbe99a0326359daee238b437938
|
|
BLAKE2b-256 checksum How to use checksums |
312162ac400b7cfed36b1421fe4c5b91f2d44d180c955f1abc7c99a5cb50de0c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.7
|