Enhanced time synchronization for drf views.
Clone ▾
| 43 B | |
| 672 B | |
| 457 B | |
| 4.3 KB |
PlusRequest
PlusRequest is a Django REST Framework (DRF) extension that enhances the standard Request with first-class support for timestamp-based synchronization and typed metadata access.
It adds a structured way to compare client and server timestamps, detect when updates are needed, and manage API headers in a consistent, testable manner.
Features
- ✅
PlusRequest: subclass of DRF’sRequestwith timestamp parsing & comparison - 🧠
TimestampOp: context-aware timestamp diff logic (raise_get, etc.) - ⚙️ Configurable via
PlusRequestConf(env vars orsettings.PLUSREQUEST_CONF) - 🧾 Typed request metadata with
Meta,PlusMeta, andDefaultMeta - 🔒 Built-in error handling for missing or invalid timestamps
Installation
pip install git+https://github.com/huncholane/django-plusrequest
Make sure your project has a valid setup.py or pyproject.toml.
Add to middleware. It's safe to add anywhere in the middleware since it only effects typing, and the functionality is lazy.
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"plusrequest.middleware.PlusRequestMiddleware",
]
Usage
Example View
from plusrequest.request import PlusRequest
def view(request: PlusRequest):
op = request.ts_builder(instance=model)
if op.client_is_newer:
return Response("No update needed.")
# else send new data
return Response(data)
Timestamp Comparison
The TimestampOp class is accessed via request.top_builder(...). It automatically:
- Extracts server timestamps from a model instance
- Parses client timestamps from headers or body
- Validates datetime format
- Raises errors or returns status flags
Supported behaviors
raise_getraise_update
Configuration
Set via environment variables or in settings.PLUSREQUEST_CONF:
| Key | Default | Description |
|---|---|---|
PLUSREQUEST_HEADER_TIMESTAMP_FIELD |
lastUpdated |
Header field used for client timestamp |
PLUSREQUEST_BODY_TIMESTAMP_FIELD |
lastUpdated |
Body field used for client timestamp |
PLUSREQUEST_INSTANCE_TIMESTAMP_FIELD |
lastUpdated |
Model field used for server timestamp |
PLUSREQUEST_NOUPDATE_CODE |
418 |
Error code raised when update is unnecessary |
PLUSREQUEST_MISSING_ACTION |
noupdate |
Action if timestamp is missing (error, allow, noupdate) |
PLUSREQUEST_DATETIME_FORMAT |
%Y-%m-%dT%H:%M:%S%z |
Timestamp parsing format |
Typed Metadata Access
Use Meta for strongly-typed access to request.META.
from plusrequest.meta import Meta
def view(request: PlusRequest):
meta: Meta = request.META
user_agent = meta.get("HTTP_USER_AGENT")
ip = meta.get("HTTP_X_REAL_IP") or meta.get("REMOTE_ADDR")
Meta Types
DefaultMeta: Core Django fields (e.g.HTTP_HOST,REQUEST_METHOD)PlusMeta: Common API headers (e.g.HTTP_AUTHORIZATION,HTTP_X_APP_VERSION)Meta: Union of both
Exceptions
InvalidClientDatetimeFieldInvalidServerDatetimeFieldNoUpdate
Raised when timestamps are missing, malformatted, or update should be skipped.
Project Structure
plusrequest/
├── request.py # PlusRequest class
├── timestamp_op.py # TimestampOp logic
├── meta.py # TypedDict for request.META
├── settings.py # Loads PlusRequestConf
├── types.py # Custom enums or aliases
License
MIT License
---
Let me know if you want:
- Examples for writing tests with `PlusRequest`
- Sphinx or `mkdocs` setup
- DRF `APIView` integration patterns