Metadata-Version: 2.4
Name: humanoid_django
Version: 0.1.0
Summary: A tiny, flexible framework layer on top of Django REST Framework.
Author: Humanoid Django Authors
License: MIT
Project-URL: Homepage, https://github.com/your-username/humanoid-django
Project-URL: Documentation, https://github.com/your-username/humanoid-django#readme
Project-URL: Issues, https://github.com/your-username/humanoid-django/issues
Keywords: django,drf,rest-framework,api,crud,permissions
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Web Environment
Classifier: Framework :: Django
Classifier: Framework :: Django :: 5.2
Classifier: Framework :: Django :: 6.0
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: Django<7.0,>=5.2
Requires-Dist: djangorestframework<4.0,>=3.15
Provides-Extra: filters
Requires-Dist: django-filter>=24.0; extra == "filters"
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == "dev"
Requires-Dist: twine>=5.0; extra == "dev"
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pytest-django>=4.8; extra == "dev"
Dynamic: license-file

# humanoid_django

`humanoid_django` is a tiny framework layer on top of **Django REST Framework**.
It is made for developers who want DRF power but do not want to repeat the same
serializer, viewset, router, pagination, search, filtering, ordering, and role
permission code in every project.

## Goals

- Create CRUD APIs in 3–4 lines.
- Keep normal DRF available when you need full control.
- Work with any model and any user-role style.
- Support simple constants from `roles.py` like `SUPER_ADMIN`, `ADMIN`, `USER`.
- Be easy for beginners, but flexible enough for real projects.

## Installation

```bash
pip install humanoid_django
```

For local development from this folder:

```bash
python -m pip install -e .
```

Add apps in `settings.py`:

```python
INSTALLED_APPS = [
    # ...
    "rest_framework",
    "humanoid_django",
]
```

Optional, for `filters()` support:

```bash
pip install "humanoid_django[filters]"
```

```python
INSTALLED_APPS = [
    # ...
    "django_filters",
]
```

## The easiest possible API

`api.py`

```python
from humanoid_django import HumanoidAPI
from .models import Product

api = HumanoidAPI()
api.resource("products", Product)

urlpatterns = api.urls
```

Main project `urls.py`:

```python
from django.urls import include, path
from products.api import urlpatterns as product_api

urlpatterns = [
    path("api/", include(product_api)),
]
```

Now you get these endpoints automatically:

```text
GET     /api/products/
POST    /api/products/
GET     /api/products/{id}/
PUT     /api/products/{id}/
PATCH   /api/products/{id}/
DELETE  /api/products/{id}/
```

## Example with roles.py

`roles.py`

```python
SUPER_ADMIN = "SUPER_ADMIN"
ADMIN = "ADMIN"
USER = "USER"
```

`api.py`

```python
from humanoid_django import HumanoidAPI
from .models import Product
from .roles import SUPER_ADMIN, ADMIN, USER

api = HumanoidAPI()

api.resource("products", Product).fields("id", "name", "price", "created_at").roles(
    default=[ADMIN, SUPER_ADMIN],
    list=[USER, ADMIN, SUPER_ADMIN],
    retrieve=[USER, ADMIN, SUPER_ADMIN],
    create=[ADMIN, SUPER_ADMIN],
    update=[ADMIN, SUPER_ADMIN],
    partial_update=[ADMIN, SUPER_ADMIN],
    destroy=[SUPER_ADMIN],
)

urlpatterns = api.urls
```

That means:

- `USER`, `ADMIN`, and `SUPER_ADMIN` can list and retrieve products.
- `ADMIN` and `SUPER_ADMIN` can create/update products.
- Only `SUPER_ADMIN` can delete products.

## Search, filter, order, optimize

```python
api.resource("products", Product) \
    .fields("id", "name", "price", "category", "created_at") \
    .search("name", "category__name") \
    .filters("category", "is_active") \
    .ordering("name", "price", "created_at", default=["-created_at"]) \
    .optimize(select=["category"])
```

Then your API supports:

```text
/api/products/?search=laptop
/api/products/?category=1
/api/products/?ordering=-price
/api/products/?fields=id,name,price
/api/products/?omit=created_at
```

## Owner-based APIs

For models with a `user`, `owner`, `created_by`, or custom owner field:

```python
api.resource("orders", Order).owner("user").roles(USER, owner=True)
```

This can restrict the queryset to the logged-in user and also allow object-level
owner permission checks.

## Use normal DRF whenever needed

You can still write a normal serializer:

```python
from rest_framework import serializers
from .models import Product

class ProductSerializer(serializers.ModelSerializer):
    class Meta:
        model = Product
        fields = ["id", "name", "price"]
```

Then use it inside Humanoid:

```python
api.resource("products", Product).serializer(ProductSerializer)
```

You can also write a normal ViewSet by extending `HumanoidModelViewSet`:

```python
from humanoid_django import HumanoidModelViewSet
from humanoid_django.permissions import allow
from .models import Product
from .roles import ADMIN

class ProductViewSet(HumanoidModelViewSet):
    model = Product
    fields = ("id", "name", "price")
    permission_classes = [allow.roles(ADMIN)]
```

## Permission helpers

```python
from humanoid_django.permissions import allow

permission_classes = [allow.roles(ADMIN, SUPER_ADMIN)]
permission_classes = [allow.owner_or_roles(ADMIN, owner_field="created_by")]
permission_classes = [allow.action_roles({"list": [USER], "destroy": [SUPER_ADMIN]})]
```

By default, `humanoid_django` looks for roles in:

- `user.role`
- `user.roles`
- `user.user_type`
- `user.type`
- Django groups, using group names as roles

You can customize that in `settings.py`:

```python
HUMANOID_DJANGO = {
    "ROLE_FIELDS": ("role", "account_type"),
    "ROLE_NAME_FIELDS": ("name", "code", "slug", "value"),
    "GROUPS_AS_ROLES": True,
    "SUPERUSER_ALWAYS_ALLOWED": True,
    "STAFF_ALWAYS_ALLOWED": False,
    "DEFAULT_PAGE_SIZE": 20,
    "MAX_PAGE_SIZE": 200,
}
```

## Response envelope, optional

By default, Humanoid keeps DRF responses normal. If you want all generated APIs
to return `{data, message, errors}`, enable:

```python
HUMANOID_DJANGO = {
    "ENVELOPE_RESPONSES": True,
}

REST_FRAMEWORK = {
    "EXCEPTION_HANDLER": "humanoid_django.exceptions.humanoid_exception_handler",
}
```

## Scaffold starter files

```bash
python manage.py humanoid_start products
```

This creates:

- `products/api.py`
- `products/roles.py`

## Build and upload to PyPI

```bash
python -m pip install --upgrade build twine
python -m build
python -m twine check dist/*
python -m twine upload dist/*
```

## Compatibility

The package metadata targets:

- Python 3.10+
- Django 5.2+
- Django 6.x
- Django REST Framework 3.15+

## Philosophy

Humanoid does not replace DRF. It removes repetitive code from common projects,
then lets you drop back into normal DRF whenever you need custom behavior.
