A Django REST API for managing research studies, participant records, and application review workflows.
- Manages studies created by researchers
- Stores participant profiles
- Handles study applications and review decisions
- Uses role-based access control (
admin,researcher) - Supports filtering, search, ordering, and pagination
- Provides asynchronous data export functionality (CSV)
This project follows a layered architecture to keep business logic clean and testable:
- Views (API layer) – handle HTTP requests/responses
- Permissions – enforce access control at the API level
- Service Layer – contains core business logic (e.g. approve/reject workflows)
- Models – database representation
Key idea:
Business logic is not implemented in views or serializers, but in dedicated service classes.
This makes the system easier to:
- test
- extend
- reuse
- Python 3
- Django 6
- Django REST Framework
- PostgreSQL 17
- Celery (background workers)
- RabbitMQ (message broker)
- Docker / Docker Compose
- Ruff (linting & formatting)
- Coverage.py (test coverage)
django-filter
research_registry/
├── backend/
│ ├── research_registry/ # Django project settings + root URLs
│ ├── accounts/ # Users, roles, auth
│ ├── studies/ # Study resources
│ ├── participants/ # Participant resources
│ ├── applications/ # Application resources + review logic
│ │ └── services/
│ │ └── application_export_service.py
│ ├── exports/ # Export system (jobs, tasks, API)
│ │ ├── models.py
│ │ ├── views.py
│ │ ├── serializers.py
│ │ ├── tasks.py
│ │ └── constants.py
│ ├── Dockerfile
│ └── requirements.txt
This project includes a production-style export system using background workers.
Export large datasets as CSV Runs asynchronously via Celery workers Uses RabbitMQ as message broker Tracks export status (pending, processing, completed, failed) Stores generated files using Django FileField Enforces user-level permissions on exported data
- User requests an export via API
- An ExportJob is created in the database
- A Celery worker processes the job asynchronously
- Data is written to a CSV file
- File is stored under /media/exports/
- User can check status and download when ready
- Clone and enter the project:
git clone <your-repo-url>
cd research_registry- Create environment file:
cp .env.example .envThen configure the .env file with your environment-specific values (e.g. database credentials, passwords, and secret keys).
- Start everything (build, migrate, init roles, seed data):
make upAPI base URL after startup:
http://localhost:8000/api/
Using Makefile:
make up # full setup
make test # run tests + coverage
make test-fast # run tests without coverage
make lint # lint code (ruff)
make format # format code
make fix # auto-fix lint issuesOpen Django shell:
docker compose exec web python manage.py shelldocker compose up -d --build
docker compose exec web python manage.py makemigrations
docker compose exec web python manage.py migrate
docker compose exec web python manage.py init_roles
docker compose exec web python manage.py seed_demo_dataCreate a superuser:
docker compose exec web python manage.py createsuperuserCreate a researcher user (interactive prompt):
docker compose exec web python manage.py create_researcherGet access and refresh tokens:
curl -X POST http://localhost:8000/api/token/ \
-H "Content-Type: application/json" \
-d '{"username":"<username>","password":"<password>"}'Refresh access token:
curl -X POST http://localhost:8000/api/token/refresh/ \
-H "Content-Type: application/json" \
-d '{"refresh":"<refresh_token>"}'Call authenticated endpoint:
curl http://localhost:8000/api/me/ \
-H "Authorization: Bearer <access_token>"All routes below reflect the current URL configuration in this repository.
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/token/ |
Obtain JWT access/refresh token pair |
POST |
/api/token/refresh/ |
Refresh JWT access token |
GET |
/api/me/ |
Current authenticated user profile |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/studies/ |
List studies |
POST |
/api/studies/ |
Create study |
GET |
/api/studies/{id}/ |
Retrieve study |
PUT |
/api/studies/{id}/ |
Replace study |
PATCH |
/api/studies/{id}/ |
Partially update study |
DELETE |
/api/studies/{id}/ |
Delete study |
Query support on list endpoint:
- Filters:
status,created_by - Search:
search(title, description) - Ordering:
ordering(created_at,title)
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/participants/ |
List participants |
POST |
/api/participants/ |
Create participant |
GET |
/api/participants/{id}/ |
Retrieve participant |
PUT |
/api/participants/{id}/ |
Replace participant |
PATCH |
/api/participants/{id}/ |
Partially update participant |
DELETE |
/api/participants/{id}/ |
Delete participant |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/applications/ |
List applications |
POST |
/api/applications/ |
Create application |
GET |
/api/applications/{id}/ |
Retrieve application |
PUT |
/api/applications/{id}/ |
Replace application |
PATCH |
/api/applications/{id}/ |
Partially update application |
DELETE |
/api/applications/{id}/ |
Delete application |
POST |
/api/applications/{id}/approve/ |
Approve application |
POST |
/api/applications/{id}/reject/ |
Reject application |
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/exports/ |
Create an asynchronous export job for a specific resource type (e.g. applications) with optional filtering. |
GET |
/api/exports/ |
List all export jobs created by the authenticated user, ordered by most recent. |
GET |
/api/exports/{id}/ |
Retrieve the status and details of a specific export job, including the download URL when available. |
Query support on list endpoint:
- Filters:
status,study,participant,reviewed_by - Search:
search(status,study__id,participant__id,reviewed_by__username) - Ordering:
ordering(id,status,reviewed_by)
| Method | Endpoint | Description |
|---|---|---|
GET |
/admin/ |
Django admin |
GET |
/api-auth/login/ |
DRF browsable API login |
GET |
/api-auth/logout/ |
DRF browsable API logout |
Default page size is 5 items per page (PageNumberPagination).
Example:
GET /api/studies/?page=2
admin: full accessresearcher: access based on ownership/business rules- anonymous users: read-only where allowed
- CSV export
- Expanded audit tooling
- Production hardening (Gunicorn/Nginx, security settings)
Educational/demo project for learning Django + DRF architecture.