Files
mizan/backends/mizan-django/README.md
Ryth Azhur 76fce2dc85 Split the registry — function/composition core + backend extensions
The original registry tangled function, channel, composition, and form
registration in a single file with polymorphic register() dispatch.
That predates the household discipline; it was the design that was
supposed to ship but didn't. Re-implementing the original intent.

cores/mizan-python/src/mizan_core/registry.py (new):
- _functions, _compositions dicts
- register() — ServerFunction-only, no polymorphic dispatch
- register_as(), register_compose()
- register_extension(name, extension) — hook interface
- get_function/get_compose/get_all_functions/get_all_compositions
- get_contexts, get_context_groups
- get_registry, get_schema — aggregate extension contributions
- validate_registry, clear_registry — cascade-clear extensions

RegistryExtension Protocol:
- schema() returns the extension's schema subdict (keyed under its name)
- clear() resets extension state (called by clear_registry)

mizan-django/src/mizan/channels/__init__.py:
- _ChannelsExtension wraps the channel _registry, plugs into core via
  register_extension('channels', ...). Schema output preserves the
  same shape codegen consumed before (snake_case keys, type+bidirectional).

mizan-django/src/mizan/forms/__init__.py:
- register_form() and get_forms() helpers moved here (were in setup/registry.py)
- Both use mizan_core.registry under the hood. Forms don't need a
  separate extension because form sub-functions register as regular
  ServerFunctions with meta.form set.

mizan-django/src/mizan/setup/registry.py: deleted.
mizan-django/src/mizan/setup/__init__.py: re-exports the registry helpers
from mizan_core.registry / mizan.channels / mizan.forms — the Django
adapter's curated public API surface stays stable for users.

Consumers updated: ~10 files imported `from mizan.setup.registry`;
all switched to direct imports from mizan_core.registry, mizan.channels,
or mizan.forms as appropriate. ChannelTests in test_core.py rewritten
to use mizan.channels.register directly (no more polymorphic
@register_as on ReactChannel subclasses).

Verified:
- mizan-core: 15/15
- mizan-django: 348 pass, 21 skip, 0 fail
- mizan-ts edge-compat: 34/34 (cross-language pin holds)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 15:21:16 -04:00

106 lines
2.1 KiB
Markdown

# mizan (Python)
Django server functions framework. See the [monorepo root](../README.md) for full documentation.
## Install
```bash
uv add "mizan[channels,allauth] @ git+https://git.impactsoundworks.com/isw/mizan.git#subdirectory=django"
```
## Setup
```python
# settings.py
INSTALLED_APPS = ["mizan", ...]
# urls.py
path("api/mizan/", include("mizan.urls"))
# asgi.py (optional, for WebSocket)
from mizan import wrap_asgi
application = wrap_asgi(get_asgi_application())
```
## Define Functions
```python
from mizan.client import client
from mizan_core.registry import register
from pydantic import BaseModel
class Output(BaseModel):
message: str
@client
def echo(request, text: str) -> Output:
return Output(message=text)
register(echo, "echo")
```
Register in `apps.py`:
```python
def ready(self):
import myapp.mizan_clients
```
## Auth
```python
@client(auth=True) # requires authentication
@client(auth='staff') # requires is_staff
@client(auth='superuser') # requires is_superuser
@client(auth=my_callable) # custom check
```
## Contexts
```python
@client(context='global') # fetched once, SSR-hydrated, becomes useCurrentUser()
@client(context='local') # fetched with params, becomes <GreetProvider>
```
## Forms
```python
from mizan.forms import mizanFormMixin, mizanFormMeta
class ContactForm(mizanFormMixin, forms.Form):
mizan = mizanFormMeta(name="contact", title="Contact Us")
name = forms.CharField()
email = forms.EmailField()
def on_submit_success(self, request):
return {"sent": True}
```
Auto-registers `contact.schema`, `contact.validate`, `contact.submit`. Generates `useContactForm()` with Zod validation.
## Channels
```python
from mizan.channels import ReactChannel
class ChatChannel(ReactChannel):
class Params(BaseModel):
room: str
class DjangoMessage(BaseModel):
text: str
def authorize(self, params):
return self.user.is_authenticated
def group(self, params):
return f"chat_{params.room}"
```
Generates `useChatChannel({ room })`.
## Running Tests
```bash
uv sync --extra dev --extra channels
uv run pytest
```