製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 README。 儲存庫 README ↗
正在載入完整 README。
檢視完整 README ↗A service contract for Django: declare an operation's parameters, permission check, validation and output once, and dispatch it from any transport - an HTTP view, an MCP tool, an agent tool, a management command or a background task.
Django is the base and the only framework it depends on. Django REST Framework is
not a dependency, and nothing in the package imports it, so a project with business
logic and no API framework can hand its operations to an agent, a command or a
queue with Django alone.
djangorestframework-services
depends on this package and is its DRF adapter; this package will never depend
on it.
No agent transport reads a spec without DRF yet. The family's MCP server
(djangorestframework-mcp-server)
and its Pydantic AI toolset
(djangorestframework-pydantic-ai)
reach specs through djangorestframework-services today, so both still require
DRF. What a tool-building transport reads off a spec besides dispatch -
affordances, paging, the agent projection of an output, progress - is here, and
transport distributions that read kernel specs with no DRF at all are planned.
Until then a project without DRF can dispatch its specs from its own views,
commands, tasks and agent tools, and no ready-made MCP server or agent toolset
serves them.
A spec as a management command is
django-spec-cli, a distribution
of its own that depends on this one: one command per registry, one subcommand
per spec, run through dispatch as a named user. A spec served from a plain
Django view, as JSON or as the page its form renders, is
django-spec-html, likewise its
own distribution.
Status: early. The public API may still change between minor releases, and every change is recorded in the changelog.
pip install django-service-specs
The package has no models and runs with no entry in INSTALLED_APPS; list
"django_service_specs" there for its translations to load. It ships its
source catalog and no translated language yet. A principal is a user of
django.contrib.auth, and a generic-relation write needs
django.contrib.contenttypes. Django 4.2 or later, on Python 3.10 or later.
Two parts need more, and each comes with an extra: the pydantic adapter, and
a selector's django-filter FilterSet:
pip install "django-service-specs[pydantic]"
pip install "django-service-specs[filter]"
One write, declared once: what it takes (a dataclass behind a Validator),
which row it acts on (an instance selector), who may run it
(permissions=[...]), and what it returns (a Presenter). Note is a model
with a title and an owner who is a user.
from dataclasses import dataclass
from typing import Any
from django_service_specs import (
DataclassPresenter,
DataclassValidator,
Parameter,
Parameters,
PermissionCheck,
SelectorKind,
SelectorSpec,
ServiceSpec,
dispatch,
present,
)
from notes.models import Note # a title, and an owner who is a user
@dataclass
class Rename: # what the operation takes
title: str
@dataclass
class NoteOut: # what it returns
id: int
title: str
class IsOwner(PermissionCheck):
message = "Only the note's owner may rename it."
def has_permission(self, principal: Any, spec: Any) -> bool:
return principal.is_authenticated
def has_object_permission(self, principal: Any, spec: Any, target: Any) -> bool:
return target.owner_id == principal.pk
def rename_note(*, instance: Note, title: str) -> Note:
instance.title = title
instance.save(update_fields=["title"])
return instance
rename_note_spec = ServiceSpec(
service=rename_note,
permissions=[IsOwner()],
validator=DataclassValidator(Rename),
instance_selector_spec=SelectorSpec(
kind=SelectorKind.RETRIEVE,
selector=lambda *, pk: Note.objects.filter(pk=pk), # the row, or none
reads=Parameters.of(Parameter("pk", "integer", required=True)),
),
presenter=DataclassPresenter(NoteOut),
)
def rename(user: Any, arguments: dict[str, Any]) -> Any:
result = dispatch(rename_note_spec, principal=user, arguments=arguments)
if result.kind == "not_found":
return None # a transport answers this in its own terms: a 404, an exit code
return present(rename_note_spec, result)
以上為 README 的開頭部分。其餘內容請閱讀原文。 檢視完整 README ↗