A lightweight, high-performance Key-Value Store built entirely on the Django framework.
This project re-imagines Redis as a RESTful web service. It provides atomic SET and GET operations, supports complex JSON data types natively, and implements a robust expiration engine (TTL) that works both lazily (on-access) and actively (via a background scheduler).
- About the Project
- Key Features
- Architecture
- Getting Started
- Usage Guide
- Background Scheduler
- Project Structure
- Roadmap
- License
I built this project to demonstrate that Django can be used for more than just standard CRUD apps. By leveraging Django's ORM for atomic locking (update_or_create) and JSONField for flexible storage, we created a thread-safe state store that can be accessed by any HTTP client.
It is designed to be a "State Microservice" for distributed systems that need to share configuration or session data without setting up a full Redis instance.
- ✅ JSON-First Storage: Store
strings,lists,integers, or nesteddictionariesnatively. - ✅ Time-To-Live (TTL): Set keys to auto-expire after
Nseconds. - ✅ Lazy Expiration: Expired keys are instantly detected and removed during
GETrequests. - ✅ Active Cleanup: A standalone background worker purges stale data to keep the DB lean.
- ✅ Atomic Writes: Handles race conditions safely using database-level locking strategies.
The system uses a Hybrid Expiration Strategy:
-
Lazy Deletion (Passive):
When a client requests a key viaGET, the server checksif now > expires_at. If true, it deletes the key immediately and returns404 Not Found. -
Active Deletion (Active):
A background script (run_scheduler.py) runs every 60 seconds to bulk-delete keys that haven't been accessed recently but are past their expiry.
- Python 3.8+
pip(Python Package Manager)
-
Clone the repository
git clone https://github.com/yourusername/django-redis-clone.git cd django-redis-clone -
Install dependencies
pip install django
-
Initialize the Database
python manage.py makemigrations python manage.py migrate
-
Start the Server
python manage.py runserver 8000
The API accepts and returns application/json. You can use curl, Postman, or any HTTP client.
Create or update a key.
Request:
curl -X POST http://127.0.0.1:8000/user-config/ \
-H "Content-Type: application/json" \
-d '{
"value": {"theme": "dark", "notifications": true}
}'Response:
{
"status": "ok",
"action": "created",
"key": "user-config",
"expires_at": null
}Request:
curl -X POST http://127.0.0.1:8000/otp-code/ \
-H "Content-Type: application/json" \
-d '{
"value": 49201,
"ttl": 60
}'Response:
{
"status": "ok",
"action": "created",
"key": "otp-code",
"expires_at": "2025-12-20T21:31:00Z"
}Retrieve a key.
Request:
curl http://127.0.0.1:8000/user-config/Response (Success):
{
"key": "user-config",
"value": {"theme": "dark", "notifications": true},
"ttl_remaining": -1
}Response (Expired or Missing):
{
"error": "Key not found (expired)"
}To prevent the database from growing infinitely with stale data, run the included scheduler. This script works on Windows, Linux, and macOS.
Run in a separate terminal window:
python run_scheduler.pyOutput:
---------------------------------------------------
Scheduler Started. Running 'cleanup_keys' every 60s.
---------------------------------------------------
Running cleanup... Successfully deleted 5 expired keys.
redis_clone/
├── db.sqlite3 # The persisted database
├── manage.py # Django entry point
├── run_scheduler.py # Background task runner (Custom Script)
├── redis_clone/ # Project Settings
│ ├── settings.py
│ └── urls.py
└── store/ # Main Application
├── models.py # KeyValue model definition
├── views.py # API logic (GET/POST)
└── management/
└── commands/
└── cleanup_keys.py # The cleanup logic
- Basic SET/GET operations
- Lazy Expiration logic
- Background Cleanup Scheduler
- Add Authentication (API Key middleware)
- Add INCR and DECR atomic operations for counters
- Dockerize the application with docker-compose
Distributed under the MIT License. See LICENSE for more information.
Built with ❤️ by Iremide Joseph Adeyanju.