Chisle
The coding-agent plugin that bills 52% of a bare model across 20 live tasks. Terse persona + tool-output compressor + context diet.
翻訳待ち
Serve django-service-specs specs over HTTP with Django REST Framework.
翻訳待ち
Loading the full README.
Read the full README ↗A service / selector layer for Django REST Framework. Serve django-service-specs kernel specs over Django REST Framework.
A kernel spec declares an operation once: the callable that runs it, the
arguments it reads, who may call it, how its input is validated and how its
result is presented. django-spec-rest serves that spec on a DRF view or
viewset, and lets DRF fill three of its seats: a serializer validates the
input (SerializerValidator), a serializer renders the result
(SerializerPresenter), and DRF permission classes decide who may call it
(DRFPermissionCheck). The same spec runs off HTTP through the kernel's own
dispatch, and on any other transport that serves kernel specs.
ServiceCreateView,
ServiceUpdateView, ServiceDeleteView, SelectorListView,
SelectorRetrieveView, ServiceViewSet, SelectorViewSet, the per-action
mixins, and @service_action / @selector_action for custom routes.drf-spectacular
integration describes each route's request and response.Full documentation: https://artui.github.io/django-spec-rest/
Coming from djangorestframework-services? The
moving page has the
import map and every change a client sees.
pip install django-spec-rest
# or, with uv:
uv add django-spec-rest
The package is not a Django app and needs no INSTALLED_APPS entry. A spec's
filter_set needs the kernel's filter extra
(pip install "django-service-specs[filter]"), and the OpenAPI integration
needs pip install "django-spec-rest[spectacular]".
A service, a selector and two serializers, all plain:
from rest_framework import serializers
from invoices.models import Invoice
def create_invoice(*, data):
return Invoice.objects.create(**data)
def list_invoices():
return Invoice.objects.all()
class InvoiceInput(serializers.Serializer):
customer = serializers.CharField(max_length=200)
amount_cents = serializers.IntegerField(min_value=0)
class InvoiceSerializer(serializers.ModelSerializer):
class Meta:
model = Invoice
fields = ("id", "customer", "amount_cents", "status")
Kernel specs with DRF in their seats, served on a viewset:
from django_service_specs import SelectorKind, SelectorSpec, ServiceSpec, Unrestricted
from rest_framework.routers import DefaultRouter
from django_spec_rest import ServiceViewSet
from django_spec_rest.service_specs.serializer_presenter import SerializerPresenter
from django_spec_rest.service_specs.serializer_validator import SerializerValidator
OPEN = (Unrestricted(),)
PRESENTER = SerializerPresenter(InvoiceSerializer)
class InvoiceViewSet(ServiceViewSet):
action_specs = {
"list": SelectorSpec(
kind=SelectorKind.LIST,
selector=list_invoices,
permissions=OPEN,
presenter=PRESENTER,
),
"create": ServiceSpec(
service=create_invoice,
validator=SerializerValidator(InvoiceInput),
permissions=OPEN,
presenter=PRESENTER,
),
}
router = DefaultRouter()
router.register("invoices", InvoiceViewSet, basename="invoice")
urlpatterns = router.urls
GET /invoices/ answers the rows rendered by InvoiceSerializer;
POST /invoices/ answers 201 with the created row, or 400 keyed by field. The
kernel refuses to dispatch a spec that declares no permissions, so
Unrestricted() says the operation is open to every caller. The
quickstart carries this
on to retrieve, update, OPTIONS and a call off HTTP.
examples/ is a runnable Django project on one resource, with a
test per behaviour: a spec on a viewset and on a standalone view, a filter read
off the query string, OPTIONS on a detail route, a refusal of each status, a
DRFPermissionCheck over HTTP and through the kernel's plain dispatch, a
caller nobody authenticated refused 401 with the first authenticator's
WWW-Authenticate (by an adapted DRF class and by a kernel PermissionCheck,
each answering a signed-in caller 403), the generated OpenAPI schema carrying
those 401 and 403 responses and the 409 a service raises, and a key one
serializer writes into the shared context that another renders. make examples
runs the whole suite, schema tests included.
cd examples
python manage.py migrate
python manage.py runserver
| Axis | Range |
|---|---|
| Python | 3.10 – 3.14 |
| Django | 4.2, 5.0, 5.1, 5.2, 6.0 |
| DRF | ≥ 3.14 |
CI runs the full Python × Django matrix with 100% coverage gating.
Pre-1.0. See CHANGELOG.md for the release history.
MIT.