dataman-engine 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dataman_engine-0.1.0/PKG-INFO +259 -0
- dataman_engine-0.1.0/README.md +221 -0
- dataman_engine-0.1.0/pyproject.toml +119 -0
- dataman_engine-0.1.0/pyproject.toml.orig +102 -0
- dataman_engine-0.1.0/src/dataman/__init__.py +18 -0
- dataman_engine-0.1.0/src/dataman/cli.py +731 -0
- dataman_engine-0.1.0/src/dataman/core/__init__.py +0 -0
- dataman_engine-0.1.0/src/dataman/core/apps.py +9 -0
- dataman_engine-0.1.0/src/dataman/core/audit.py +171 -0
- dataman_engine-0.1.0/src/dataman/core/auth.py +106 -0
- dataman_engine-0.1.0/src/dataman/core/crypto.py +173 -0
- dataman_engine-0.1.0/src/dataman/core/fields.py +120 -0
- dataman_engine-0.1.0/src/dataman/core/masking.py +107 -0
- dataman_engine-0.1.0/src/dataman/core/middleware.py +46 -0
- dataman_engine-0.1.0/src/dataman/core/models.py +175 -0
- dataman_engine-0.1.0/src/dataman/core/permissions.py +110 -0
- dataman_engine-0.1.0/src/dataman/core/router.py +112 -0
- dataman_engine-0.1.0/src/dataman/core/signals.py +56 -0
- dataman_engine-0.1.0/src/dataman/core/templates/admin/dashboard.html +1399 -0
- dataman_engine-0.1.0/src/dataman/core/templates/admin/login.html +377 -0
- dataman_engine-0.1.0/src/dataman/core/urls.py +472 -0
- dataman_engine-0.1.0/src/dataman/core/views.py +678 -0
- dataman_engine-0.1.0/src/dataman/django_setup.py +192 -0
- dataman_engine-0.1.0/src/dataman/py.typed +0 -0
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dataman-engine
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A dynamic, headless data layer framework built on Django and DRF for instant CRUD APIs and custom business logic.
|
|
5
|
+
Keywords: django,rest,api,crud,headless,generator,scaffold
|
|
6
|
+
Author: Vikash G
|
|
7
|
+
Author-email: Vikash G <vikashgraja@gmail.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Environment :: Web Environment
|
|
12
|
+
Classifier: Framework :: Django
|
|
13
|
+
Classifier: Framework :: Django :: 5.0
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
20
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
22
|
+
Requires-Dist: django>=6.0.2
|
|
23
|
+
Requires-Dist: djangorestframework>=3.15.0
|
|
24
|
+
Requires-Dist: click>=8.1.7
|
|
25
|
+
Requires-Dist: python-dotenv>=1.0.1
|
|
26
|
+
Requires-Dist: django-filter>=25.1
|
|
27
|
+
Requires-Dist: requests>=2.32.3
|
|
28
|
+
Requires-Dist: pydantic>=2.10.5
|
|
29
|
+
Requires-Dist: drf-spectacular>=0.28.0
|
|
30
|
+
Requires-Dist: dj-database-url>=2.3.0
|
|
31
|
+
Requires-Dist: inflection>=0.5.1
|
|
32
|
+
Requires-Dist: uvicorn>=0.34.0
|
|
33
|
+
Requires-Dist: cryptography>=42.0.0
|
|
34
|
+
Requires-Python: >=3.13
|
|
35
|
+
Project-URL: Homepage, https://github.com/vikashg/dataman
|
|
36
|
+
Project-URL: Repository, https://github.com/vikashg/dataman.git
|
|
37
|
+
Description-Content-Type: text/markdown
|
|
38
|
+
|
|
39
|
+
# DataMan (Data MiddleMan)
|
|
40
|
+
|
|
41
|
+
**DataMan** is a dynamic, CLI-driven backend framework built on top of Django and Django REST Framework. It eliminates the boilerplate of writing standard CRUD APIs, routing, and serializers by allowing you to scaffold endpoints instantly from the command line while preserving your ability to inject custom business logic and strict validation whenever you need it.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Features
|
|
46
|
+
- **Instant CRUD APIs**: Automatically generate RESTful APIs from simple model definitions.
|
|
47
|
+
- **CLI Scaffolding**: Setup projects and table structures with simple commands.
|
|
48
|
+
- **Hook-Based Business Logic**: Inject custom logic via `service.py` (`before_create`, `after_delete`, etc.) without touching serializers or viewsets.
|
|
49
|
+
- **Validation Injection**: Run custom data validators before database commits via `validation.py`.
|
|
50
|
+
- **Fine-Grained Authentication**: Lock down endpoints using granular, table-and-operation specific scopes (e.g., `customer:read`, `order:write`).
|
|
51
|
+
- **Dynamic Routing & Pagination**: Built-in DRF integration with default pagination and dynamic URL mappings.
|
|
52
|
+
- **Production Health Probes**: Built-in `/health/live/` and `/health/ready/` endpoints for Kubernetes/Docker container monitoring, database vitality, and migration checks.
|
|
53
|
+
- **Multi-Database Routing**: Organize tables by database directory (`<database>/<table>`) and route traffic, migrations, and health checks across isolated databases.
|
|
54
|
+
- **ASGI High-Concurrency Engine**: Built-in `uvicorn` server execution mode (`dataman server start --asgi`) for high throughput asynchronous performance.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Installation
|
|
59
|
+
|
|
60
|
+
Ensure you have Python 3.13+ installed.
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# Using uv (Recommended)
|
|
64
|
+
uv add dataman-engine
|
|
65
|
+
|
|
66
|
+
# Using pip
|
|
67
|
+
pip install dataman-engine
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Quick Start
|
|
73
|
+
|
|
74
|
+
Get a full REST API running in under a minute!
|
|
75
|
+
|
|
76
|
+
### 1. Initialize a Project
|
|
77
|
+
Run the following in an empty directory to scaffold the necessary environment:
|
|
78
|
+
```bash
|
|
79
|
+
dataman init
|
|
80
|
+
```
|
|
81
|
+
This generates your project configuration:
|
|
82
|
+
```text
|
|
83
|
+
my-project/
|
|
84
|
+
├── .env # Environment variables & secrets
|
|
85
|
+
├── database.py # Database connection & pooling (SQLite default, Postgres, MySQL)
|
|
86
|
+
├── config.py # Project settings (Hosts, CORS, pagination, custom middleware)
|
|
87
|
+
└── tables/ # API tables & database migrations
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### 2. Configure Database & Project Settings (Optional)
|
|
91
|
+
Easily customize your database backend in `database.py` (e.g., PostgreSQL or MySQL) and global settings in `config.py`:
|
|
92
|
+
```python
|
|
93
|
+
# database.py
|
|
94
|
+
DATABASES = {
|
|
95
|
+
"default": dj_database_url.config(
|
|
96
|
+
default="postgres://user:pass@localhost:5432/my_db",
|
|
97
|
+
conn_max_age=600,
|
|
98
|
+
)
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 3. Create a Table
|
|
103
|
+
Scaffold a new table (e.g., `Customer`) with full CRUD operations (`-o crud`):
|
|
104
|
+
```bash
|
|
105
|
+
dataman create table Customer -o crud
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### 4. Define Your Fields
|
|
109
|
+
Open the generated `tables/Customer/models.py` and define your Django fields:
|
|
110
|
+
```python
|
|
111
|
+
from django.db import models
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class Customer(models.Model):
|
|
115
|
+
name = models.CharField(max_length=255)
|
|
116
|
+
email = models.EmailField(unique=True)
|
|
117
|
+
created_at = models.DateTimeField(auto_now_add=True)
|
|
118
|
+
|
|
119
|
+
class Meta:
|
|
120
|
+
db_table = "customer"
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### 4. Migrate and Run
|
|
124
|
+
Apply the database migrations and start the server!
|
|
125
|
+
```bash
|
|
126
|
+
dataman makemigration
|
|
127
|
+
dataman migrate
|
|
128
|
+
|
|
129
|
+
# Start development WSGI server
|
|
130
|
+
dataman server start
|
|
131
|
+
|
|
132
|
+
# OR start high-concurrency production ASGI server with Uvicorn
|
|
133
|
+
dataman server start --asgi --host 0.0.0.0 --port 8000 --workers 4
|
|
134
|
+
```
|
|
135
|
+
*Your API is now live at `http://127.0.0.1:8000/api/customer/`!*
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Advanced Usage
|
|
140
|
+
|
|
141
|
+
DataMan abstracts away the boring parts but leaves you full control over the important logic. Every table generated under `tables/<TableName>/` comes with four critical files:
|
|
142
|
+
|
|
143
|
+
### 1. `config.py` (API Settings)
|
|
144
|
+
Control exactly what HTTP methods are exposed and whether the table requires authentication.
|
|
145
|
+
```python
|
|
146
|
+
# tables/Customer/config.py
|
|
147
|
+
ALLOWED_OPERATIONS = ["C", "R"] # Only allow Create (POST) and Read (GET)
|
|
148
|
+
REQUIRE_AUTH = True # Lock down this endpoint
|
|
149
|
+
DEPTH = 1 # Automatically serialize nested Foreign Key relationships on read (GET)
|
|
150
|
+
|
|
151
|
+
# Advanced Filtering, Search & Ordering
|
|
152
|
+
FILTER_FIELDS = {
|
|
153
|
+
"price": ["gte", "lte", "exact"],
|
|
154
|
+
"name": ["icontains", "exact"],
|
|
155
|
+
"is_active": ["exact"],
|
|
156
|
+
} # Or simple list: ["name", "email"]
|
|
157
|
+
SEARCH_FIELDS = ["name", "email"]
|
|
158
|
+
ORDERING_FIELDS = ["created_at", "price"]
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### 2. Authentication & Scopes
|
|
162
|
+
If `REQUIRE_AUTH = True`, clients must provide a token in the `Authorization` header. You can generate fine-grained access tokens directly from the CLI:
|
|
163
|
+
```bash
|
|
164
|
+
dataman users create-token MyFrontendService --scopes customer:read,customer:create
|
|
165
|
+
```
|
|
166
|
+
Use the token in your requests:
|
|
167
|
+
```http
|
|
168
|
+
Authorization: Token <your_generated_token_key>
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### 3. `validation.py` (Data Validation)
|
|
172
|
+
Validate incoming JSON payloads before they are passed to the database. Raise `ValidationError` to immediately return a `400 Bad Request`.
|
|
173
|
+
```python
|
|
174
|
+
# tables/Customer/validation.py
|
|
175
|
+
from rest_framework.exceptions import ValidationError
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def validate(data):
|
|
179
|
+
if "admin" in data.get("name", "").lower():
|
|
180
|
+
raise ValidationError({"name": "Reserved keyword used."})
|
|
181
|
+
|
|
182
|
+
# You can also mutate incoming data
|
|
183
|
+
data["name"] = data["name"].strip().title()
|
|
184
|
+
return data
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### 4. `service.py` (Pre/Post Hooks)
|
|
188
|
+
Run business logic right before or after the database commits a transaction. Available hooks: `before_create`, `after_create`, `before_update`, `after_update`, `before_destroy`, `after_destroy`.
|
|
189
|
+
|
|
190
|
+
```python
|
|
191
|
+
# tables/Customer/service.py
|
|
192
|
+
def before_create(data):
|
|
193
|
+
# E.g., hash a password, trigger a background task, or enforce rules
|
|
194
|
+
if not data.get("email"):
|
|
195
|
+
raise ValueError("Email is strictly required")
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def after_create(instance):
|
|
199
|
+
# instance is the saved Django model object
|
|
200
|
+
print(f"Successfully created customer: {instance.name}")
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### 5. Health Checks & Readiness Probes
|
|
204
|
+
DataMan comes with built-in health check endpoints designed for cloud platforms, load balancers, and orchestrators (Kubernetes, AWS ECS, Docker):
|
|
205
|
+
* `GET /health/live/` (or `/api/health/live/`): Liveness probe returning `200 OK` indicating the process is alive.
|
|
206
|
+
* `GET /health/ready/` (or `/api/health/ready/`): Readiness probe validating active database connection integrity and unapplied migrations (returns `200 OK` or `503 Service Unavailable`).
|
|
207
|
+
* `GET /health/` (or `/api/health/`): Unified health status with database latency metrics.
|
|
208
|
+
|
|
209
|
+
### 6. Multi-Database Architecture
|
|
210
|
+
Organize large projects with isolated physical databases:
|
|
211
|
+
|
|
212
|
+
```text
|
|
213
|
+
my_project/
|
|
214
|
+
├── database.py
|
|
215
|
+
├── config.py
|
|
216
|
+
├── analytics_db/
|
|
217
|
+
│ ├── events/
|
|
218
|
+
│ │ ├── models.py
|
|
219
|
+
│ │ └── config.py
|
|
220
|
+
│ └── metrics/
|
|
221
|
+
│ ├── models.py
|
|
222
|
+
│ └── config.py
|
|
223
|
+
└── core_db/
|
|
224
|
+
└── users/
|
|
225
|
+
├── models.py
|
|
226
|
+
└── config.py
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
1. Create a database:
|
|
230
|
+
```bash
|
|
231
|
+
dataman create database analytics_db
|
|
232
|
+
```
|
|
233
|
+
2. Scaffold a table bound to that database:
|
|
234
|
+
```bash
|
|
235
|
+
dataman create table events --database analytics_db
|
|
236
|
+
```
|
|
237
|
+
3. Run migrations across all databases (or target a single database):
|
|
238
|
+
```bash
|
|
239
|
+
dataman migrate
|
|
240
|
+
# or
|
|
241
|
+
dataman migrate --database analytics_db
|
|
242
|
+
```
|
|
243
|
+
Endpoints are automatically registered at both `api/<table_name>/` and namespaced `api/<database_name>/<table_name>/`.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## Testing
|
|
248
|
+
|
|
249
|
+
DataMan is rigorously tested with **95%+ branch coverage**, verifying extreme edge cases, token validations, and dynamic hook executions.
|
|
250
|
+
|
|
251
|
+
To run the test suite:
|
|
252
|
+
```bash
|
|
253
|
+
uv run pytest tests/ -v
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## License
|
|
259
|
+
MIT License
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# DataMan (Data MiddleMan)
|
|
2
|
+
|
|
3
|
+
**DataMan** is a dynamic, CLI-driven backend framework built on top of Django and Django REST Framework. It eliminates the boilerplate of writing standard CRUD APIs, routing, and serializers by allowing you to scaffold endpoints instantly from the command line while preserving your ability to inject custom business logic and strict validation whenever you need it.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
- **Instant CRUD APIs**: Automatically generate RESTful APIs from simple model definitions.
|
|
9
|
+
- **CLI Scaffolding**: Setup projects and table structures with simple commands.
|
|
10
|
+
- **Hook-Based Business Logic**: Inject custom logic via `service.py` (`before_create`, `after_delete`, etc.) without touching serializers or viewsets.
|
|
11
|
+
- **Validation Injection**: Run custom data validators before database commits via `validation.py`.
|
|
12
|
+
- **Fine-Grained Authentication**: Lock down endpoints using granular, table-and-operation specific scopes (e.g., `customer:read`, `order:write`).
|
|
13
|
+
- **Dynamic Routing & Pagination**: Built-in DRF integration with default pagination and dynamic URL mappings.
|
|
14
|
+
- **Production Health Probes**: Built-in `/health/live/` and `/health/ready/` endpoints for Kubernetes/Docker container monitoring, database vitality, and migration checks.
|
|
15
|
+
- **Multi-Database Routing**: Organize tables by database directory (`<database>/<table>`) and route traffic, migrations, and health checks across isolated databases.
|
|
16
|
+
- **ASGI High-Concurrency Engine**: Built-in `uvicorn` server execution mode (`dataman server start --asgi`) for high throughput asynchronous performance.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
Ensure you have Python 3.13+ installed.
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# Using uv (Recommended)
|
|
26
|
+
uv add dataman-engine
|
|
27
|
+
|
|
28
|
+
# Using pip
|
|
29
|
+
pip install dataman-engine
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Quick Start
|
|
35
|
+
|
|
36
|
+
Get a full REST API running in under a minute!
|
|
37
|
+
|
|
38
|
+
### 1. Initialize a Project
|
|
39
|
+
Run the following in an empty directory to scaffold the necessary environment:
|
|
40
|
+
```bash
|
|
41
|
+
dataman init
|
|
42
|
+
```
|
|
43
|
+
This generates your project configuration:
|
|
44
|
+
```text
|
|
45
|
+
my-project/
|
|
46
|
+
├── .env # Environment variables & secrets
|
|
47
|
+
├── database.py # Database connection & pooling (SQLite default, Postgres, MySQL)
|
|
48
|
+
├── config.py # Project settings (Hosts, CORS, pagination, custom middleware)
|
|
49
|
+
└── tables/ # API tables & database migrations
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 2. Configure Database & Project Settings (Optional)
|
|
53
|
+
Easily customize your database backend in `database.py` (e.g., PostgreSQL or MySQL) and global settings in `config.py`:
|
|
54
|
+
```python
|
|
55
|
+
# database.py
|
|
56
|
+
DATABASES = {
|
|
57
|
+
"default": dj_database_url.config(
|
|
58
|
+
default="postgres://user:pass@localhost:5432/my_db",
|
|
59
|
+
conn_max_age=600,
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 3. Create a Table
|
|
65
|
+
Scaffold a new table (e.g., `Customer`) with full CRUD operations (`-o crud`):
|
|
66
|
+
```bash
|
|
67
|
+
dataman create table Customer -o crud
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 4. Define Your Fields
|
|
71
|
+
Open the generated `tables/Customer/models.py` and define your Django fields:
|
|
72
|
+
```python
|
|
73
|
+
from django.db import models
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class Customer(models.Model):
|
|
77
|
+
name = models.CharField(max_length=255)
|
|
78
|
+
email = models.EmailField(unique=True)
|
|
79
|
+
created_at = models.DateTimeField(auto_now_add=True)
|
|
80
|
+
|
|
81
|
+
class Meta:
|
|
82
|
+
db_table = "customer"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### 4. Migrate and Run
|
|
86
|
+
Apply the database migrations and start the server!
|
|
87
|
+
```bash
|
|
88
|
+
dataman makemigration
|
|
89
|
+
dataman migrate
|
|
90
|
+
|
|
91
|
+
# Start development WSGI server
|
|
92
|
+
dataman server start
|
|
93
|
+
|
|
94
|
+
# OR start high-concurrency production ASGI server with Uvicorn
|
|
95
|
+
dataman server start --asgi --host 0.0.0.0 --port 8000 --workers 4
|
|
96
|
+
```
|
|
97
|
+
*Your API is now live at `http://127.0.0.1:8000/api/customer/`!*
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Advanced Usage
|
|
102
|
+
|
|
103
|
+
DataMan abstracts away the boring parts but leaves you full control over the important logic. Every table generated under `tables/<TableName>/` comes with four critical files:
|
|
104
|
+
|
|
105
|
+
### 1. `config.py` (API Settings)
|
|
106
|
+
Control exactly what HTTP methods are exposed and whether the table requires authentication.
|
|
107
|
+
```python
|
|
108
|
+
# tables/Customer/config.py
|
|
109
|
+
ALLOWED_OPERATIONS = ["C", "R"] # Only allow Create (POST) and Read (GET)
|
|
110
|
+
REQUIRE_AUTH = True # Lock down this endpoint
|
|
111
|
+
DEPTH = 1 # Automatically serialize nested Foreign Key relationships on read (GET)
|
|
112
|
+
|
|
113
|
+
# Advanced Filtering, Search & Ordering
|
|
114
|
+
FILTER_FIELDS = {
|
|
115
|
+
"price": ["gte", "lte", "exact"],
|
|
116
|
+
"name": ["icontains", "exact"],
|
|
117
|
+
"is_active": ["exact"],
|
|
118
|
+
} # Or simple list: ["name", "email"]
|
|
119
|
+
SEARCH_FIELDS = ["name", "email"]
|
|
120
|
+
ORDERING_FIELDS = ["created_at", "price"]
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### 2. Authentication & Scopes
|
|
124
|
+
If `REQUIRE_AUTH = True`, clients must provide a token in the `Authorization` header. You can generate fine-grained access tokens directly from the CLI:
|
|
125
|
+
```bash
|
|
126
|
+
dataman users create-token MyFrontendService --scopes customer:read,customer:create
|
|
127
|
+
```
|
|
128
|
+
Use the token in your requests:
|
|
129
|
+
```http
|
|
130
|
+
Authorization: Token <your_generated_token_key>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### 3. `validation.py` (Data Validation)
|
|
134
|
+
Validate incoming JSON payloads before they are passed to the database. Raise `ValidationError` to immediately return a `400 Bad Request`.
|
|
135
|
+
```python
|
|
136
|
+
# tables/Customer/validation.py
|
|
137
|
+
from rest_framework.exceptions import ValidationError
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def validate(data):
|
|
141
|
+
if "admin" in data.get("name", "").lower():
|
|
142
|
+
raise ValidationError({"name": "Reserved keyword used."})
|
|
143
|
+
|
|
144
|
+
# You can also mutate incoming data
|
|
145
|
+
data["name"] = data["name"].strip().title()
|
|
146
|
+
return data
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### 4. `service.py` (Pre/Post Hooks)
|
|
150
|
+
Run business logic right before or after the database commits a transaction. Available hooks: `before_create`, `after_create`, `before_update`, `after_update`, `before_destroy`, `after_destroy`.
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
# tables/Customer/service.py
|
|
154
|
+
def before_create(data):
|
|
155
|
+
# E.g., hash a password, trigger a background task, or enforce rules
|
|
156
|
+
if not data.get("email"):
|
|
157
|
+
raise ValueError("Email is strictly required")
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def after_create(instance):
|
|
161
|
+
# instance is the saved Django model object
|
|
162
|
+
print(f"Successfully created customer: {instance.name}")
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### 5. Health Checks & Readiness Probes
|
|
166
|
+
DataMan comes with built-in health check endpoints designed for cloud platforms, load balancers, and orchestrators (Kubernetes, AWS ECS, Docker):
|
|
167
|
+
* `GET /health/live/` (or `/api/health/live/`): Liveness probe returning `200 OK` indicating the process is alive.
|
|
168
|
+
* `GET /health/ready/` (or `/api/health/ready/`): Readiness probe validating active database connection integrity and unapplied migrations (returns `200 OK` or `503 Service Unavailable`).
|
|
169
|
+
* `GET /health/` (or `/api/health/`): Unified health status with database latency metrics.
|
|
170
|
+
|
|
171
|
+
### 6. Multi-Database Architecture
|
|
172
|
+
Organize large projects with isolated physical databases:
|
|
173
|
+
|
|
174
|
+
```text
|
|
175
|
+
my_project/
|
|
176
|
+
├── database.py
|
|
177
|
+
├── config.py
|
|
178
|
+
├── analytics_db/
|
|
179
|
+
│ ├── events/
|
|
180
|
+
│ │ ├── models.py
|
|
181
|
+
│ │ └── config.py
|
|
182
|
+
│ └── metrics/
|
|
183
|
+
│ ├── models.py
|
|
184
|
+
│ └── config.py
|
|
185
|
+
└── core_db/
|
|
186
|
+
└── users/
|
|
187
|
+
├── models.py
|
|
188
|
+
└── config.py
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
1. Create a database:
|
|
192
|
+
```bash
|
|
193
|
+
dataman create database analytics_db
|
|
194
|
+
```
|
|
195
|
+
2. Scaffold a table bound to that database:
|
|
196
|
+
```bash
|
|
197
|
+
dataman create table events --database analytics_db
|
|
198
|
+
```
|
|
199
|
+
3. Run migrations across all databases (or target a single database):
|
|
200
|
+
```bash
|
|
201
|
+
dataman migrate
|
|
202
|
+
# or
|
|
203
|
+
dataman migrate --database analytics_db
|
|
204
|
+
```
|
|
205
|
+
Endpoints are automatically registered at both `api/<table_name>/` and namespaced `api/<database_name>/<table_name>/`.
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Testing
|
|
210
|
+
|
|
211
|
+
DataMan is rigorously tested with **95%+ branch coverage**, verifying extreme edge cases, token validations, and dynamic hook executions.
|
|
212
|
+
|
|
213
|
+
To run the test suite:
|
|
214
|
+
```bash
|
|
215
|
+
uv run pytest tests/ -v
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## License
|
|
221
|
+
MIT License
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "dataman-engine"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "A dynamic, headless data layer framework built on Django and DRF for instant CRUD APIs and custom business logic."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
requires-python = ">=3.13"
|
|
8
|
+
classifiers = [
|
|
9
|
+
"Development Status :: 4 - Beta",
|
|
10
|
+
"Environment :: Console",
|
|
11
|
+
"Environment :: Web Environment",
|
|
12
|
+
"Framework :: Django",
|
|
13
|
+
"Framework :: Django :: 5.0",
|
|
14
|
+
"Intended Audience :: Developers",
|
|
15
|
+
"Operating System :: OS Independent",
|
|
16
|
+
"Programming Language :: Python",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.13",
|
|
19
|
+
"Topic :: Internet :: WWW/HTTP",
|
|
20
|
+
"Topic :: Internet :: WWW/HTTP :: Dynamic Content",
|
|
21
|
+
"Topic :: Software Development :: Libraries :: Application Frameworks",
|
|
22
|
+
]
|
|
23
|
+
keywords = [
|
|
24
|
+
"django",
|
|
25
|
+
"rest",
|
|
26
|
+
"api",
|
|
27
|
+
"crud",
|
|
28
|
+
"headless",
|
|
29
|
+
"generator",
|
|
30
|
+
"scaffold",
|
|
31
|
+
]
|
|
32
|
+
dependencies = [
|
|
33
|
+
"django>=6.0.2",
|
|
34
|
+
"djangorestframework>=3.15.0",
|
|
35
|
+
"click>=8.1.7",
|
|
36
|
+
"python-dotenv>=1.0.1",
|
|
37
|
+
"django-filter>=25.1",
|
|
38
|
+
"requests>=2.32.3",
|
|
39
|
+
"pydantic>=2.10.5",
|
|
40
|
+
"drf-spectacular>=0.28.0",
|
|
41
|
+
"dj-database-url>=2.3.0",
|
|
42
|
+
"inflection>=0.5.1",
|
|
43
|
+
"uvicorn>=0.34.0",
|
|
44
|
+
"cryptography>=42.0.0",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
[[project.authors]]
|
|
48
|
+
name = "Vikash G"
|
|
49
|
+
email = "vikashgraja@gmail.com"
|
|
50
|
+
|
|
51
|
+
[project.scripts]
|
|
52
|
+
dataman = "dataman.cli:cli"
|
|
53
|
+
|
|
54
|
+
[project.urls]
|
|
55
|
+
Homepage = "https://github.com/vikashg/dataman"
|
|
56
|
+
Repository = "https://github.com/vikashg/dataman.git"
|
|
57
|
+
|
|
58
|
+
[tool.coverage.run]
|
|
59
|
+
branch = true
|
|
60
|
+
concurrency = ["multiprocessing"]
|
|
61
|
+
sigterm = true
|
|
62
|
+
|
|
63
|
+
[tool.uv.build-backend]
|
|
64
|
+
module-name = "dataman"
|
|
65
|
+
|
|
66
|
+
[tool.ruff]
|
|
67
|
+
line-length = 88
|
|
68
|
+
target-version = "py310"
|
|
69
|
+
exclude = [
|
|
70
|
+
".venv",
|
|
71
|
+
"venv",
|
|
72
|
+
"__pycache__",
|
|
73
|
+
"build",
|
|
74
|
+
"dist",
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
[tool.ruff.lint]
|
|
78
|
+
select = [
|
|
79
|
+
"E",
|
|
80
|
+
"W",
|
|
81
|
+
"F",
|
|
82
|
+
"I",
|
|
83
|
+
"UP",
|
|
84
|
+
"B",
|
|
85
|
+
"C4",
|
|
86
|
+
"SIM",
|
|
87
|
+
]
|
|
88
|
+
ignore = ["E501"]
|
|
89
|
+
|
|
90
|
+
[tool.ruff.format]
|
|
91
|
+
quote-style = "double"
|
|
92
|
+
indent-style = "space"
|
|
93
|
+
skip-magic-trailing-comma = false
|
|
94
|
+
line-ending = "auto"
|
|
95
|
+
|
|
96
|
+
[tool.bandit]
|
|
97
|
+
exclude_dirs = [
|
|
98
|
+
"tests",
|
|
99
|
+
".venv",
|
|
100
|
+
]
|
|
101
|
+
skips = ["B101"]
|
|
102
|
+
|
|
103
|
+
[tool.pytest.ini_options]
|
|
104
|
+
testpaths = ["tests"]
|
|
105
|
+
addopts = "-v --tb=short"
|
|
106
|
+
|
|
107
|
+
[build-system]
|
|
108
|
+
requires = ["uv_build>=0.10.6,<0.13.0"]
|
|
109
|
+
build-backend = "uv_build"
|
|
110
|
+
|
|
111
|
+
[dependency-groups]
|
|
112
|
+
dev = [
|
|
113
|
+
"bandit>=1.9.4",
|
|
114
|
+
"playwright>=1.62.0",
|
|
115
|
+
"pre-commit>=4.6.1",
|
|
116
|
+
"pytest>=9.1.1",
|
|
117
|
+
"pytest-cov>=7.1.0",
|
|
118
|
+
"ruff>=0.16.1",
|
|
119
|
+
]
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "dataman-engine"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "A dynamic, headless data layer framework built on Django and DRF for instant CRUD APIs and custom business logic."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
authors = [
|
|
8
|
+
{ name = "Vikash G", email = "vikashgraja@gmail.com" }
|
|
9
|
+
]
|
|
10
|
+
requires-python = ">=3.13"
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Development Status :: 4 - Beta",
|
|
13
|
+
"Environment :: Console",
|
|
14
|
+
"Environment :: Web Environment",
|
|
15
|
+
"Framework :: Django",
|
|
16
|
+
"Framework :: Django :: 5.0",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Operating System :: OS Independent",
|
|
19
|
+
"Programming Language :: Python",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.13",
|
|
22
|
+
"Topic :: Internet :: WWW/HTTP",
|
|
23
|
+
"Topic :: Internet :: WWW/HTTP :: Dynamic Content",
|
|
24
|
+
"Topic :: Software Development :: Libraries :: Application Frameworks",
|
|
25
|
+
]
|
|
26
|
+
keywords = ["django", "rest", "api", "crud", "headless", "generator", "scaffold"]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
dependencies = [
|
|
30
|
+
"django>=6.0.2",
|
|
31
|
+
"djangorestframework>=3.15.0",
|
|
32
|
+
"click>=8.1.7",
|
|
33
|
+
"python-dotenv>=1.0.1",
|
|
34
|
+
"django-filter>=25.1",
|
|
35
|
+
"requests>=2.32.3",
|
|
36
|
+
"pydantic>=2.10.5",
|
|
37
|
+
"drf-spectacular>=0.28.0",
|
|
38
|
+
"dj-database-url>=2.3.0",
|
|
39
|
+
"inflection>=0.5.1",
|
|
40
|
+
"uvicorn>=0.34.0",
|
|
41
|
+
"cryptography>=42.0.0",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[project.scripts]
|
|
45
|
+
dataman = "dataman.cli:cli"
|
|
46
|
+
|
|
47
|
+
[project.urls]
|
|
48
|
+
Homepage = "https://github.com/vikashg/dataman"
|
|
49
|
+
Repository = "https://github.com/vikashg/dataman.git"
|
|
50
|
+
|
|
51
|
+
[tool.coverage.run]
|
|
52
|
+
branch = true
|
|
53
|
+
concurrency = ["multiprocessing"]
|
|
54
|
+
sigterm = true
|
|
55
|
+
[build-system]
|
|
56
|
+
requires = ["uv_build>=0.10.6,<0.13.0"]
|
|
57
|
+
build-backend = "uv_build"
|
|
58
|
+
|
|
59
|
+
[tool.uv.build-backend]
|
|
60
|
+
module-name = "dataman"
|
|
61
|
+
|
|
62
|
+
[dependency-groups]
|
|
63
|
+
dev = [
|
|
64
|
+
"bandit>=1.9.4",
|
|
65
|
+
"playwright>=1.62.0",
|
|
66
|
+
"pre-commit>=4.6.1",
|
|
67
|
+
"pytest>=9.1.1",
|
|
68
|
+
"pytest-cov>=7.1.0",
|
|
69
|
+
"ruff>=0.16.1",
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
[tool.ruff]
|
|
73
|
+
line-length = 88
|
|
74
|
+
target-version = "py310"
|
|
75
|
+
exclude = [".venv", "venv", "__pycache__", "build", "dist"]
|
|
76
|
+
|
|
77
|
+
[tool.ruff.lint]
|
|
78
|
+
select = [
|
|
79
|
+
"E",
|
|
80
|
+
"W",
|
|
81
|
+
"F",
|
|
82
|
+
"I",
|
|
83
|
+
"UP",
|
|
84
|
+
"B",
|
|
85
|
+
"C4",
|
|
86
|
+
"SIM",
|
|
87
|
+
]
|
|
88
|
+
ignore = ["E501"]
|
|
89
|
+
|
|
90
|
+
[tool.ruff.format]
|
|
91
|
+
quote-style = "double"
|
|
92
|
+
indent-style = "space"
|
|
93
|
+
skip-magic-trailing-comma = false
|
|
94
|
+
line-ending = "auto"
|
|
95
|
+
|
|
96
|
+
[tool.bandit]
|
|
97
|
+
exclude_dirs = ["tests", ".venv"]
|
|
98
|
+
skips = ["B101"]
|
|
99
|
+
|
|
100
|
+
[tool.pytest.ini_options]
|
|
101
|
+
testpaths = ["tests"]
|
|
102
|
+
addopts = "-v --tb=short"
|