Metadata-Version: 2.4
Name: humanoid-crud
Version: 0.1.0
Summary: One-line CRUD registration for Django REST Framework. Built on top of DRF's mixins/generics so you never have to write a Serializer, ViewSet, or router.register() by hand for the common case.
Author: Your Name
License-Expression: MIT
Project-URL: Homepage, https://github.com/yourname/humanoid-crud
Project-URL: Repository, https://github.com/yourname/humanoid-crud
Keywords: django,django-rest-framework,drf,crud,api,rest
Classifier: Framework :: Django
Classifier: Framework :: Django :: 4
Classifier: Framework :: Django :: 5
Classifier: Programming Language :: Python :: 3
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: djangorestframework>=3.14
Provides-Extra: filters
Requires-Dist: django-filter>=23.0; extra == "filters"
Dynamic: license-file

# humanoid-crud

A one-line CRUD registrar for Django REST Framework. Built **on top of** DRF's
mixins/generics (it generates real `ModelSerializer` and `ModelViewSet`
classes for you) — the point isn't to avoid mixins, it's that you never have
to write or stack them by hand.

## Install

```bash
pip install humanoid-crud
```

If you want `filterset_fields` (exact-match filtering), install the extra:

```bash
pip install humanoid-crud[filters]
```

Note: the **package name on PyPI** is `humanoid-crud` (hyphen, matching PyPI
convention), but you **import it in Python** as `humanoid_crud` (underscore,
since hyphens aren't valid in Python identifiers). This is normal — the same
is true for packages like `django-rest-framework` → `import rest_framework`.

## The problem this solves

The normal DRF CRUD recipe for one model is:

```python
# serializers.py
class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = '__all__'

# views.py
class BookViewSet(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

# urls.py
router.register('books', BookViewSet)
```

Three files, three pieces of boilerplate, for every single model.
`humanoid_crud` collapses that to:

```python
import humanoid_crud
humanoid_crud.register(Book)
```

## Quick start

1. `pip install humanoid-crud`
2. Add `'rest_framework'` to `INSTALLED_APPS` in `settings.py` if it isn't
   already there.
3. Create a small file — e.g. `myapp/api.py` — where you register your
   models:

```python
# myapp/api.py
import humanoid_crud
from myapp.models import Book, Author

humanoid_crud.register(Author)
humanoid_crud.register(Book)
```

4. In your project's `urls.py`, import that file (so the registrations run)
   and add the generated routes:

```python
from django.contrib import admin
from django.urls import path

from myapp import api          # running this import triggers registration
import humanoid_crud

urlpatterns = [
    path('admin/', admin.site.urls),
] + humanoid_crud.urls
```

That's it. You now have, for each model:

| Method | URL              | Action          |
|--------|-------------------|-----------------|
| GET    | `/books/`         | list            |
| POST   | `/books/`         | create          |
| GET    | `/books/<pk>/`     | retrieve        |
| PUT    | `/books/<pk>/`     | full update     |
| PATCH  | `/books/<pk>/`     | partial update  |
| DELETE | `/books/<pk>/`     | delete          |

All validation, 404 handling, and FK integrity checks are standard DRF
behavior — nothing is hidden or changed, just wired up for you.

## Going beyond the default

Every option is optional — pass only what you need:

```python
from rest_framework.permissions import IsAuthenticated

humanoid_crud.register(
    Book,
    fields=["title", "author", "price"],     # restrict exposed fields
    read_only_fields=["created_at"],
    permissions=[IsAuthenticated],            # default is AllowAny — lock this down!
    search_fields=["title"],                  # enables ?search=
    ordering_fields=["price", "created_at"],  # enables ?ordering=
    filterset_fields=["author"],              # exact-match filtering (needs the [filters] extra)
    lookup="slug",                            # use a non-pk field in the URL
    url="library-books",                      # custom URL segment
)
```

### Escape hatch: bring your own serializer or viewset

If one model needs custom logic (e.g. a custom `create()`, extra validation,
nested writes), you don't lose `humanoid_crud`'s URL registration — just hand
it your own class:

```python
class BookViewSet(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def perform_create(self, serializer):
        serializer.save(added_by=self.request.user)

humanoid_crud.register(Book, viewset_class=BookViewSet)
```

The generated classes are ordinary `ModelSerializer` / `ModelViewSet`
subclasses — if you ever outgrow the one-liner for a specific model, you
write that one model the normal DRF way and `humanoid_crud` still handles
the routing.

## Important: default permissions are wide open

If you don't pass `permissions=[...]`, every registered model defaults to
`AllowAny` — anyone can read and write it, no login required. Fine for local
prototyping. **Set explicit permissions before deploying anything real.**

## License

MIT
