Skip to main content

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, and max_show_all (default 200) is the most that the "Show all" link will show at once.
  • The page is set by the <prefix>-p query 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; otherwise ImproperlyConfigured is 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-rows management 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, and make_range template tags (from excel_tags), replaced by inline_pagination
  • django.contrib.humanize is no longer required
  • load_excel: the same-filename prompt now respects --skip-existing and --replace-existing; files are loaded in a single transaction; rows are inserted in bulk; warn when a file pattern matches nothing
  • from_timestamp: integer timestamps are now read as UTC (they were read in local time); unparseable strings raise ValueError; aware strings work
  • the JSON encoder handles numpy booleans
  • require Django 4.2 or newer; drop the unused psycopg2 and pytz dependencies
  • 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)

Table of built distributions (wheels) for minchin.django.excel 1.1.0
File Interpreter ABI Platform
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

Release history Release notifications | RSS feed

This release

1.1.0 This release

1 release file

1.0.0

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page