FairDM
A Django framework for building FAIR research data portals with minimal code.
FairDM makes it trivial for research teams to define domain-specific sample and measurement models and run a fully functional data portal without writing views, URL routing, or frontend code.
🎯 What is FairDM?
FairDM is an opinionated Django framework (not a library) designed specifically for research data management. It enables researchers with basic Python skills to:
- Define custom domain models for samples and measurements
- Get a fully functional web portal without writing views or templates
- Ensure data follows FAIR principles (Findable, Accessible, Interoperable, Reusable)
- Manage research projects, datasets, and contributors out of the box
- Import/export data in multiple formats with zero configuration
- Control access with fine-grained object-level permissions
Scope & philosophy
What FairDM is
A batteries-included Django framework for building research data portals. You describe your samples and measurements as Django models, register them, and get the portal without writing that layer yourself: views, URLs, forms, filters, tables, admin and API.
What FairDM is deliberately not
- Not a library of parts. It is opinionated and owns the application shell. If you want to assemble your own stack from independent components, this is the wrong starting point.
- Not a generic CMS. The core model (projects, datasets, samples, measurements and contributors) is fixed, because it is what makes portals interoperable and citable.
- Not a single portal. Domain-specific schemas belong in portals that build on FairDM, not in the framework itself.
- Not a JavaScript application. The server-rendered baseline is the product, not a fallback.
- Not a formal publisher. Publishing a dataset in FairDM makes it visible to other users of the portal. Sending metadata to a data publisher and receiving a DOI in return is a separate act, and it belongs to an addon rather than the core.
- Not the home of every feature. The core stays small and the framework grows through addons. A capability that only some portals need is an addon, not a core concern.
When principles collide
- Configuration over code — declarative model registration with sensible defaults.
- Domain-first modelling — accurate scientific representation outranks framework convenience.
- Progressive complexity — registering a model works on its own. Custom forms, filters and views come later, and only for the portals that need them.
- No frontend knowledge required — a working portal must not depend on template or JS skills.
- FAIR by design — metadata, stable identifiers and machine access are built in, not added on.
- A stable backbone beats a fast one — research portals outlive their funding, so the core model changes slowly and deliberately.
Where the framework is headed is a separate question from what it is. That lives in GOALS.md.
Requirements
- Python 3.13 or later.
- Django 6.0.
🚀 Quick Start
Prerequisites
- Python 3.13+
- uv for dependency management
- PostgreSQL (recommended) or SQLite for development
Installation
# Clone the repository
git clone https://github.com/FAIR-DM/fairdm.git
cd fairdm
# Install dependencies with uv
uv sync
# Activate the virtual environment
source .venv/bin/activate
# Run database migrations
uv run python manage.py migrate
# Create a superuser
uv run python manage.py createsuperuser
# Run the development server
uv run python manage.py runserver
Visit http://localhost:8000 to see your portal!
📦 Core Concepts
Projects, Datasets, Samples & Measurements
FairDM organizes research data using a hierarchical structure:
Project
└── Dataset
├── Sample (your custom types)
│ └── Measurement (your custom types)
└── Sample
└── Measurement
- Project: Top-level container for research initiatives
- Dataset: Collection of related samples with shared metadata
- Sample: Domain-specific sample types (e.g., RockSample, WaterSample)
- Measurement: Domain-specific measurements on samples (e.g., XRFMeasurement)
Portal Configuration
A portal gets its entire Django configuration from one call:
# config/settings.py
import fairdm
fairdm.setup(apps=["myportal"], addons=["fairdm_discussions"])
FairDM's settings are production-grade in every environment. Each environment is an override layered on top, named by DJANGO_ENV and applied only if it exists — so config/development.py beside your settings module tunes development, and an environment nobody ships a module for simply gets the production baseline. In production, configuration that would leave the portal unsafe stops it starting.
See Configuration for the layer order, the environment variables and manage.py show_config.
Model Registration
The heart of FairDM is its registry system. Define your models, register them, and get automatic:
- ✅ Create/Read/Update/Delete views
- ✅ List tables with sorting and filtering
- ✅ Forms with Bootstrap 5 styling
- ✅ REST API endpoints (optional)
- ✅ Import/Export functionality
- ✅ Admin integration
Example: Registering a Custom Sample
# myapp/models.py
from fairdm.core.models import Sample
from django.db import models
class RockSample(Sample):
"""Custom sample type for geological specimens."""
rock_type = models.CharField(max_length=100)
collection_date = models.DateField()
weight_grams = models.DecimalField(max_digits=10, decimal_places=2)
# myapp/config.py
from fairdm.core.sample.config import BaseSampleConfiguration
from fairdm.registry import register
from .models import RockSample
@register
class RockSampleConfig(BaseSampleConfiguration):
model = RockSample
fields = ["name", "rock_type", "collection_date", "weight_grams", "location"]
Listing location gives the type's form the location input, which reads signed decimal
degrees in WGS 84.
BaseSampleConfiguration is the recommended base for a specimen type's registry configuration —
it declares the shared fields list every generated component falls back to, so you only state it
once. A configuration that relies on the registry auto-detecting a different field list per
component (table vs. form vs. filter set) should subclass the plain ModelConfiguration instead.
That's it! You now have:
- A working web interface for managing rock samples
- Sortable/filterable tables
- Create/update/delete forms
- Import/export to CSV/Excel
- REST API endpoints (if enabled)
🎨 Features
✨ Auto-Generated Components
For every registered model, FairDM automatically generates:
| Component | Library | Purpose |
|---|---|---|
| Forms | Django Forms + Crispy Forms | Create/edit with Bootstrap 5 styling |
| Tables | django-tables2 | Sortable, paginated lists |
| Filters | django-filter | Advanced filtering UI |
| Serializers | Django REST Framework | JSON API responses |
| Resources | django-import-export | CSV/Excel import/export |
| Admin | Django Admin | Optional admin interface |
🔐 Permissions & Access Control
- Object-level permissions via django-guardian
- Role-based access (viewer, editor, manager) at Project/Dataset level
- Public/private dataset visibility controls
- Add contributors to a project or dataset, including unclaimed profiles for people without accounts yet
📊 Data Import/Export
- Formats: CSV, Excel (XLSX), JSON, ODS
- Background processing: Large imports via Celery tasks
- Validation: Automatic field validation and error reporting
- Templates: Export sample templates for data collection
🔌 Plugin System
Extend FairDM with custom functionality:
- Add analysis panels to detail views
- Create custom visualizations
- Integrate third-party tools
- Build domain-specific workflows
🌍 Modern Frontend Stack
- django-mvp — Shared application shell built on Tailwind CSS and daisyUI
- daisy-cotton-ext — Page blocks the landing page is built from
- django-mvp-compliance — Legal documents kept in the database, and a record of who agreed to them
- HTMX — Dynamic interactions without writing JavaScript
- Alpine.js — Lightweight reactivity for complex interactions
- Django Cotton — Reusable component-based templates
📚 Documentation
Full documentation is available at: https://fairdm.readthedocs.io/en/latest/
Documentation Sections
- Developers — Build and deploy a research portal on FairDM
- Administrators — Run a portal: people, roles, content review and configuration checks
- Users — Add, edit and publish research data in a portal
- Contributing — Contribute to FairDM framework development
🧪 Demo Application
Explore a working example in the demo/ directory:
# The demo app showcases:
# - Custom Sample and Measurement models
# - Model registration and configuration
# - Custom forms, tables, and filters
# - Plugin development examples
The demo app serves as executable documentation and demonstrates best practices for building portals with FairDM.
🛠️ Development
Running Tests
# Run the full test suite
uv run pytest
# Run with coverage
uv run pytest --cov=fairdm --cov-report=html
# Run specific test file
uv run pytest tests/test_registry/test_config.py
# Run the reference application's tests on their own (they run by default too)
uv run pytest demo/tests
# Run with verbose output
uv run pytest -v
# Run in a single process (tests are parallel by default)
uv run pytest -n0
Code Quality
FairDM uses Ruff for linting and formatting:
# Lint the codebase
uv run ruff check .
# Format code
uv run ruff format .
# Check type hints with mypy
uv run mypy fairdm
Project Commands
Useful Invoke tasks (see tasks.py):
# Show available tasks
uv run invoke -l
# Run database migrations
uv run invoke migrate
# Create test data
uv run invoke create-test-data
# Build documentation
uv run invoke docs
🏗️ Technology Stack
Core Framework
- Django 6.0 — Web framework
- Python 3.13+ — Programming language
- PostgreSQL — Database (recommended)
- Redis — Caching and task queue
Key Dependencies
- django-polymorphic — Polymorphic model inheritance
- django-guardian — Object-level permissions
- django-tables2 — Table rendering
- django-filter — Filtering system
- django-import-export — Data import/export
- django-htmx — HTMX integration
- django-cotton — Component-based templates
- celery — Background task processing
See pyproject.toml for the complete dependency list.
Changelog
See CHANGELOG.md.
📄 License
This project is licensed under the MIT License — see the LICENSE file for details.
🤝 Contributing
We welcome contributions! See our Contributing Guide for:
- Development workflow: Install git hooks to prevent CI failures
- Code style and conventions: Ruff formatting (120 char lines)
- Testing requirements: pytest with >80% coverage goal
- Pull request process: Pre-push validation ensures CI passes
Before your first push, install git hooks to run CI checks locally:
uv run invoke install-hooks
This prevents CI failures by running the same linting and formatting checks locally.
🌟 Project Status
FairDM is under active development. Current focus areas:
- ✅ Core framework and registry system
- ✅ Model registration and auto-generation
- ✅ Permissions and access control
- 🚧 Plugin system expansion
- 🚧 REST API enhancements
- 🚧 Advanced data visualization
- 📋 Cloud deployment guides
- 📋 Extended documentation
📞 Support & Community
- Documentation: https://fairdm.readthedocs.io/en/latest/
- Issues: https://github.com/FAIR-DM/fairdm/issues
- GitHub: https://github.com/FAIR-DM/fairdm
Made with ❤️ for the research community
Metadata
Release files for fairdm 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| fairdm-0.3.0.tar.gz | 682.3 kB | With provenance | Details for fairdm-0.3.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| fairdm-0.3.0-py3-none-any.whl | Python 3 | none | any | Details for fairdm-0.3.0-py3-none-any.whl |
Total release size: 1.6 MB
Release files / fairdm-0.3.0.tar.gz
| Download URL | fairdm-0.3.0.tar.gz |
|---|---|
| Size | 682.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
44fc264282133c0e1b4f1dc9cc5cdb105cda7e228035e0ce6620f3a6a1311ed2
|
|
BLAKE2b-256 checksum How to use checksums |
b2258497bc1701d19764c5c70060a5de9aa5ed84e64036b4900314e6decc9540
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 28, 2026.
Transparency logRelease files / fairdm-0.3.0-py3-none-any.whl
| Download URL | fairdm-0.3.0-py3-none-any.whl |
|---|---|
| Size | 911.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
75dd89006e885f248db7e5ac710f1fc51870f81006c7a8bab2ca47873b28d3f1
|
|
BLAKE2b-256 checksum How to use checksums |
865f74d7bdcc192f58b281b7e764f158d058059d8da33f16acf4a4503291db5d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 28, 2026.
Transparency logSecurity for fairdm 0.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for fairdm-0.3.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 28, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.