django-import-export
Import and export data for any Django model, with admin UI integration and per-row diff previews.
Repository Health
Technical Analysis
django-import-export is a Django application and library for moving data into and out of Django models. It defines a declarative Resource class (mirroring the feel of a Django ModelForm) that maps model fields to import/export representations, then relies on the tablib library to read and write CSV, XLSX, JSON, YAML, HTML, and pandas DataFrames through that single interface.
Beyond the programmatic API, the library ships a full Django admin integration: mixing ImportExportModelAdmin into an existing ModelAdmin adds import and export UI to the changelist page, including a preview step before committing an import, per-row create/update/skip/delete handling, and a diff view (powered by Google’s diff-match-patch) showing exactly what each row will change. Natural-key export, many-to-many and foreign-key field widgets, and Celery-backed async imports round out the feature set for teams moving data between environments or letting non-technical admin users manage bulk data safely.
What You Get
- A declarative
Resource/ModelResourceAPI for mapping model fields to import/export columns, in the same style as a Django ModelForm - Format support for CSV, XLSX, JSON, YAML, HTML, ODS, and pandas DataFrames via the underlying
tabliblibrary - Admin integration mixins (
ImportExportModelAdmin,ImportMixin,ExportMixin) that add import/export UI, a preview step, and per-row diffs to the Django admin changelist - Per-row result reporting (create/update/skip/delete/error) so a bulk import can partially succeed instead of aborting on the first bad row
- Foreign-key, many-to-many, and natural-key aware widgets for converting between flat file values and related model instances
- Optional Celery integration for running large imports asynchronously
Common Use Cases
- Letting non-technical admin users upload a CSV or Excel file to bulk-create or bulk-update records from the Django admin
- Scheduling external cron jobs that import or export project data on a fixed cadence
- Migrating reference data between environments using natural-key exports that stay portable across databases
- Building a one-off migration layer to move data from another platform (e.g. WordPress) into a Django-backed system
- Giving a subset of users import/export access via Django’s permission system without exposing the full admin
Under The Hood
Architecture
A declarative metaclass (DeclarativeMetaclass / ModelDeclarativeMetaclass in declarative.py) builds Resource and ModelResource classes the same way Django’s own model metaclass builds models, collecting Field declarations and a Meta options class. ModelResource ties that field list to a live Django model via instance_loaders.py (locating the row being updated) and a Diff class in resources.py that captures pre/post field values for the admin preview. Admin integration lives in admin.py, where ImportMixin/ExportMixin (backed by BaseImportMixin/BaseExportMixin in mixins.py) hook into ModelAdmin.changelist_view to add import/export URLs, forms (forms.py: ImportForm, ConfirmImportForm, SelectableFieldsExportForm), and pluggable temp-file storage (tmp_storages.py). Field-level value conversion is isolated in widgets.py, which defines a Widget subclass per data type (foreign key, many-to-many, JSON, date, etc.) so the Resource layer never deals with raw strings directly. Per-row outcomes flow through results.py (Result, RowResult, Error), letting a bulk import report partial success instead of failing atomically. Because every downstream Resource subclass depends on the field list assembled by the declarative metaclass, changes to that mechanism would ripple through diffing, widgets, and the admin forms simultaneously.
Tech Stack
Requires Python 3.10+ and Django 5.2+, with the project’s classifiers explicitly tracking Django 6.0 and 6.1 as well — a deliberate current-Django-only support policy. Runtime dependencies are minimal: tablib>=3.7.0 supplies the actual format readers/writers (CSV, XLSX, JSON, YAML, HTML, ODS, pandas), and diff-match-patch powers the admin’s per-row diff rendering. Optional extras (tablib[cli], [ods], [pandas], [xls], [xlsx], [yaml]) let consumers pull in only the serialization backends they need rather than installing everything by default. The package is built with setuptools and versioned via setuptools-scm directly from git tags rather than a hardcoded version string. Documentation is built with Sphinx and the Read the Docs theme, and is hosted on Read the Docs via a checked-in .readthedocs.yaml.
Code Quality
The test suite lives under a dedicated tests/ Django project with its own settings, models, admin, and forms, so tests exercise the admin integration against a real running Django app rather than isolated unit stubs. tox.ini and a docker-compose.yml for Postgres/MySQL drive a real cross-database, cross-Python-version test matrix in CI, and coverage is tracked via .coveragerc and uploaded to Coveralls, with the README explicitly claiming full coverage. Style is enforced through a pinned pre-commit stack — django-upgrade, pyupgrade, black, isort, and flake8 with flake8-comprehensions — but there is no static type checker configured, and the codebase leans on tests and linting rather than type hints for correctness. Import errors are captured per-row into Error/RowResult objects instead of raised, so a single bad row degrades a bulk import gracefully rather than aborting the batch; naming follows Django’s own idioms (Meta inner classes, get_* accessors).
API Design
The core idea is porting Django’s own declarative-class ergonomics — the pattern users already know from ModelForm and Model — onto import/export: define a Resource with a Meta, mix ImportExportModelAdmin into an existing ModelAdmin, and get a working import/export UI with preview and diffing essentially for free. The format abstraction itself is delegated to tablib rather than reinvented, so the library’s real value is depth and polish of integration rather than a novel underlying mechanism: natural-key export for portability between environments, a diff view built on Google’s diff-match-patch, optional Celery-backed async imports, and configurable create/update/skip/delete handling per row. It reads as a comprehensive, well-integrated tool built on a conventional idea rather than a technically novel one.