djmvc_api¶
djmvc_api is an optional package that adds:
A JSON API on the same URLs as the HTML CRUD views (REST verbs, no DRF).
Bearer token authentication (no session cookie, no CSRF on token requests).
Swagger 2.0 schema, Swagger UI, login, and token management under
/api/.
Core JSON handlers live in djmvc; this package adds discovery, schema/UI,
tokens, and auth middleware.
JSON API (core djmvc)¶
Every ModelController exposes JSON on its existing routes.
HTML behaviour is unchanged.
Content negotiation¶
ViewMixin checks wants_json() in
dispatch():
GET / POST — JSON when
Accept: application/jsonorContent-Type: application/json.PUT / PATCH / DELETE — always routed to
json_*handlers (HTML only uses GET and POST).
REST mapping¶
Operation |
HTTP method |
Example ( |
|---|---|---|
List |
|
|
Detail |
|
|
Create |
|
|
Update |
|
|
Delete |
|
|
POST to update or delete URLs with a JSON body returns 405 with an
allowed_methods hint — use the proper verb instead.
Anonymous JSON requests receive 401 with {"detail": "Authentication required"}
(not an HTML login redirect).
Session clients (browser or test client with cookies) still use the session and must send a CSRF token on mutating requests, same as standard Django.
Routes¶
djmvc_api.djmvc registers a single ApiController
on djmvc.site. All package URLs live under /api/:
URL |
View |
|---|---|
|
|
|
|
|
|
|
|
Enable the package¶
Add djmvc_api to INSTALLED_APPS and register the Bearer middleware
(required for token auth and CSRF exemption):
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"djmvc_api.middleware.BearerCsrfMiddleware", # before CSRF
"django.middleware.locale.LocaleMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"djmvc_api.middleware.BearerUserMiddleware", # after session auth
"django.middleware.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
Run migrations after enabling the app:
python manage.py migrate
The example project already includes both; see
src/djmvc_example/settings.py.
Optional install extra (placeholder for future dependencies):
pip install djmvc[api]
Bearer authentication¶
How it works¶
Two middleware classes cooperate (all logic stays in djmvc_api):
BearerCsrfMiddleware(beforeCsrfViewMiddleware) — ifAuthorization: Bearer <token>is valid, setsrequest._dont_enforce_csrf_checksand stashes the token.BearerUserMiddleware(afterAuthenticationMiddleware) — setsrequest.userandrequest.authfrom the stashed token.
HTML forms on the same URLs still require CSRF when using session cookies.
Obtaining a token¶
Quick 1-hour token — POST /api/login/ with JSON credentials (no CSRF,
no prior session):
curl -X POST http://localhost:8000/api/login/ \
-H 'Content-Type: application/json' \
-d '{"username": "su", "password": "su"}'
Response:
{
"token": "<raw-key-shown-once>",
"expires": "2026-06-29T14:00:00+00:00",
"prefix": "AbCdEfGh"
}
Named / long-lived token — log in via HTML, open /api/token/create/, submit
the form (session + CSRF). The raw key is shown once in a success message; only
the prefix is stored for display in the list.
Using a token¶
curl http://localhost:8000/item/ \
-H 'Accept: application/json' \
-H 'Authorization: Bearer <token>'
Mutating requests (POST, PUT, PATCH, DELETE) work without a CSRF
header when the Bearer token is valid.
Token model¶
Token stores a SHA-256 hash of the key (never the
plaintext). Fields: user, name, prefix, created, optional
expires, last_used.
Non-superusers see only their own tokens (list, detail, delete).
Superusers see all tokens.
Django permissions:
view_token,add_token,delete_token(nochange— tokens are immutable).Revoke via HTML delete or
DELETE /api/token/<pk>/delete/with a Bearer token.
Swagger¶
GET /api/schema/— OpenAPI/Swagger 2.0 JSON listing every JSON-capable route (not filtered by the current user’s permissions). Bearer auth is required to execute protected operations.GET /api/— Swagger UI (vendored static assets). Use Try it out onPOST /api/login/to obtain a token; Swagger UI stores it automatically (persistAuthorization) and sendsAuthorization: Bearer …on other operations. You can also click Authorize and paste a token manually.CRUD operations document
BearerAuthinsecurityDefinitions.POST /api/login/is documented without Bearer security (it issues tokens).
Serialization¶
ModelController provides serialize()
and json_fields on each controller. Override json_fields or add
get_<field>_json hooks to control the JSON shape.
API reference (modules)¶
- class djmvc_api.views.ApiLoginView(**kwargs)[source]¶
Bases:
ViewExchange username/password for a short-lived Bearer token.
Constructor. Called in the URLconf; can contain helpful extra keyword arguments, and other things.
- dispatch(request, *args, **kwargs)¶
Redirect anonymous users to login; return 403 when permission denied.
- class djmvc_api.views.TokenCreateView(**kwargs)[source]¶
Bases:
CreateViewCreate a named API token via HTML form (raw key shown once).
Constructor. Called in the URLconf; can contain helpful extra keyword arguments, and other things.
- class djmvc_api.views.TokenController[source]¶
Bases:
ModelController
- class djmvc_api.views.SchemaView(**kwargs)[source]¶
Bases:
ViewServe a Swagger 2.0 schema for JSON-capable routes.
Constructor. Called in the URLconf; can contain helpful extra keyword arguments, and other things.
- class djmvc_api.views.SwaggerUIView(**kwargs)[source]¶
Bases:
TemplateViewRender Swagger UI for the generated schema.
Constructor. Called in the URLconf; can contain helpful extra keyword arguments, and other things.
- class djmvc_api.views.ApiController[source]¶
Bases:
Controller
- class djmvc_api.models.Token(*args, **kwargs)[source]¶
Bases:
ModelBearer token for JSON API access without session or CSRF.
- classmethod generate(user, name, expires=None)[source]¶
Create a token row and return
(instance, raw_key)(shown once).
- exception DoesNotExist¶
Bases:
ObjectDoesNotExist
- exception MultipleObjectsReturned¶
Bases:
MultipleObjectsReturned
- exception NotUpdated¶
Bases:
ObjectNotUpdated,DatabaseError
Bearer token middleware for djmvc_api.
BearerCsrfMiddleware must run before
django.middleware.csrf.CsrfViewMiddleware.
BearerUserMiddleware must run after
django.contrib.auth.middleware.AuthenticationMiddleware.
- djmvc_api.middleware.parse_bearer_header(request)[source]¶
Return the Bearer token from
Authorization, orNone.