API Documentation¶
Django Cast provides a comprehensive REST API for content management, media handling, and theme customization. The API supports both traditional Django session authentication and enables headless CMS usage.
Overview¶
The API is available at /api/ and includes:
Media management (audio, video, images)
Content access via Wagtail API
Faceted search capabilities
Theme management
Comment moderation data export
Authentication¶
Authenticated endpoints use Django session authentication (for example /api/videos/,
/api/audios/, and /api/comment_training_data/).
Browsable-API login/logout routes are project-specific. In the example project they are:
/api-auth/login//api-auth/logout/
Public endpoints (no authentication required) include:
Podlove audio format
Player configuration
Theme listing and theme update
Wagtail pages and images
Facet counts
Endpoints¶
Media Management¶
Videos
List and create videos:
GET /api/videos/
POST /api/videos/
Retrieve or delete a video:
GET /api/videos/{id}/
DELETE /api/videos/{id}/
Upload video file:
POST /api/upload_video/
Example response:
{
"id": 1,
"url": "http://localhost:8000/api/videos/1/",
"original": "http://localhost:8000/media/cast_videos/demo.mp4",
"poster": "http://localhost:8000/media/cast_videos/poster/poster_abcd.jpg",
"poster_thumbnail": "http://localhost:8000/media/images/poster.width-300.jpg"
}
Audio
List and create audio files:
GET /api/audios/
POST /api/audios/
Retrieve or delete audio:
GET /api/audios/{id}/
DELETE /api/audios/{id}/
Podlove player format (public):
GET /api/audios/podlove/{id}/
GET /api/audios/podlove/{id}/post/{post_id}/
Returns audio data formatted for the Podlove Web Player, including chapters,
transcripts, and a top-level contributors list. Contributors are derived
from non-blank transcript speaker/voice labels in first-appearance
order; the Podlove Web Player resolves transcript segment speakers against
them and renders their names:
"contributors": [
{"id": "Speaker 1", "name": "Speaker 1"}
]
Audio list/detail responses include these serializer fields:
{
"id": 12,
"name": "Episode 12",
"file_formats": "m4a mp3",
"url": "http://localhost:8000/api/audios/12/",
"podlove": "http://localhost:8000/api/audios/podlove/12/",
"mp3": "http://localhost:8000/media/cast_audio/episode-12.mp3"
}
Player configuration:
GET /api/audios/player_config/
GET /api/audios/player_config/?color_scheme=dark
Returns player theme and configuration settings. The color_scheme query
parameter accepts light or dark and can be used by themes with
client-side color mode switching.
Content Access¶
Wagtail Pages API
Access page content with filtering:
GET /api/wagtail/pages/
GET /api/wagtail/pages/{id}/
Standard Wagtail filters:
type: Filter by page type (e.g.,cast.Post,cast.Episode)child_of: Filter to only include direct children of the page with this IDdescendant_of: Filter to include all descendants of the page with this IDtranslation_of: Filter to only include translations of the page with this IDfields: Comma-separated list of fields to include in responseorder: Ordering field (prefix with-for descending)slug: Filter by slug (exact match)show_in_menus: Filter pages shown in menussearch: Full-text search (note: when usinguse_post_filter=true, this uses Django Cast’s enhanced search)limit: Number of results per pageoffset: Number of results to skip
Django Cast custom filters (requires use_post_filter=true):
use_post_filter: Set totrueto enable Django Cast’s enhanced filteringdate_facets: Filter by year-month (format:YYYY-MM)category_facets: Filter by category slugtag_facets: Filter by tag slugdate_after: Filter posts after date (format:YYYY-MM-DD)date_before: Filter posts before date (format:YYYY-MM-DD)o: Ordering by visible_date (use-visible_datefor descending)
Example requests:
Standard Wagtail filtering:
GET /api/wagtail/pages/?type=cast.Post&child_of=4
Enhanced Django Cast filtering:
GET /api/wagtail/pages/?type=cast.Post&use_post_filter=true&category_facets=tech&date_after=2024-01-01
Filter posts by month:
GET /api/wagtail/pages/?type=cast.Post&use_post_filter=true&date_facets=2024-03
Combined filters:
GET /api/wagtail/pages/?type=cast.Post&child_of=4&use_post_filter=true&tag_facets=python&date_facets=2024-03
Images API
Access images:
GET /api/wagtail/images/
GET /api/wagtail/images/{id}/
Search and Discovery¶
Facet Counts
List blogs that expose the detail endpoint:
GET /api/facet_counts/
If cast is mounted at /cast/, this becomes /cast/api/facet_counts/.
Example list response:
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 4,
"url": "http://localhost:8000/cast/api/facet_counts/4/"
}
]
}
Detail endpoint supports two response modes:
Legacy mode (default)¶
Request:
GET /api/facet_counts/{blog_id}/
Optional filter params are passed through the same filterset as the blog list:
search, date_after, date_before, date_facets, category_facets, tag_facets, o.
Example:
GET /api/facet_counts/4/?search=python&tag_facets=django
Legacy response shape:
{
"id": 4,
"url": "http://localhost:8000/cast/api/facet_counts/4/",
"facet_counts": {
"date_facets": [
{"slug": "2026-02", "name": "2026-02", "count": 2}
],
"category_facets": [
{"slug": "til", "name": "Today I Learned", "count": 1}
],
"tag_facets": [
{"slug": "django", "name": "django", "count": 1}
]
}
}
Modal mode¶
Request:
GET /api/facet_counts/{blog_id}/?mode=modal
Supported modal selection params:
search, date_facets, category_facets, tag_facets, o.
Example:
GET /api/facet_counts/4/?mode=modal&search=python&tag_facets=django&category_facets=til
Modal response shape:
{
"mode": "modal",
"result_count": 1,
"groups": {
"date_facets": {
"selected": "",
"all_count": 1,
"options": [
{"slug": "2026-02", "name": "2026-02", "count": 1},
{"slug": "2026-01", "name": "2026-01", "count": 0}
]
},
"tag_facets": {
"selected": "django",
"all_count": 2,
"options": [
{"slug": "django", "name": "django", "count": 1},
{"slug": "python", "name": "python", "count": 1}
]
},
"category_facets": {
"selected": "til",
"all_count": 2,
"options": [
{"slug": "til", "name": "Today I Learned", "count": 1},
{"slug": "weeknotes", "name": "WeekNotes", "count": 1}
]
}
}
}
Notes:
Only
mode=modalenables modal responses; unknown modes fall back to legacy output.Group keys are limited to configured facet groups from
CAST_FILTERSET_FACETSintersected with:date_facets,tag_facets,category_facets.Legacy mode uses conjunctive counts (fully filtered result set).
Modal mode uses disjunctive per-group counts (temporarily excludes the group being counted).
optionsinclude zero-count values so modal UIs can keep disabled choices visible.ois accepted for URL-state parity but does not change modal counts.date_after/date_beforeare part of the list filterset, but are not currently applied in modal mode.
Theme Management¶
List available themes:
GET /api/themes/
Update selected theme:
POST /api/update_theme/
Content-Type: application/json
{"theme_slug": "bootstrap5"}
The theme-update endpoint is session-based and does not require authentication with django-cast’s default DRF configuration. It validates the submitted theme slug and stores the selection using the same theme-selection flow as the frontend theme switcher.
Pagination¶
List endpoints support pagination:
Default page size: 40
Maximum page size: 200
Query parameters:
page,pageSize
Example:
GET /api/videos/?page=2&pageSize=20
Response format:
{
"count": 100,
"next": "http://example.com/api/videos/?page=3",
"previous": "http://example.com/api/videos/?page=1",
"results": [...]
}
File Uploads¶
File upload endpoints accept multipart/form-data:
const formData = new FormData();
formData.append('original', fileInput.files[0]);
fetch('/api/upload_video/', {
method: 'POST',
body: formData,
credentials: 'include' // Include session cookie
});
For POST /api/audios/, send audio format fields such as m4a, mp3,
oga, or opus (plus optional metadata like title/subtitle).
Error Handling¶
The API returns standard HTTP status codes:
200 OK: Success201 Created: Resource created400 Bad Request: Invalid request data401 Unauthorized: Authentication required403 Forbidden: Permission denied404 Not Found: Resource not found500 Internal Server Error: Server error
Error responses include a detail message:
{
"detail": "Authentication credentials were not provided."
}
Using the API¶
JavaScript Example¶
Fetching posts with facets:
async function fetchPosts(categorySlug, page = 1) {
const response = await fetch(
`/api/wagtail/pages/?type=cast.Post&child_of=4&use_post_filter=true&category_facets=${categorySlug}&page=${page}`,
{ credentials: 'include' }
);
return await response.json();
}
Python Client Example¶
Using the API from Python with httpx:
import httpx
# Create client for session persistence
with httpx.Client() as client:
# Request modal facet counts for a specific blog
response = client.get(
"https://example.com/api/facet_counts/4/",
params={
"mode": "modal",
"search": "python",
"tag_facets": "django",
},
)
facet_data = response.json()
Headless CMS Usage¶
Django Cast can function as a headless CMS by:
Using the Wagtail Pages API to fetch content
Implementing a frontend application (React, Vue, etc.)
Optionally using theme packages like
cast-vue
Example Vue.js integration:
// Fetch blog posts
const posts = await fetch('/api/wagtail/pages/?type=cast.Post')
.then(r => r.json());
// Get facet counts for filtering
const facets = await fetch('/api/facet_counts/1/')
.then(r => r.json());
Performance Considerations¶
Use field limiting to reduce payload size:
?fields=title,slug,dateImplement client-side caching for static content
Use pagination for large result sets
Facet counts are optimized at the repository level
Security Notes¶
All media endpoints filter by authenticated user
CSRF protection is enabled for state-changing operations
File uploads are validated for type and size
Images API includes null byte protection
Comment Moderation¶
Export training data for spam filter:
Returns comment data for training the Naive Bayes spam classifier.
This endpoint is restricted to staff users. Anonymous and authenticated non-staff users receive
403 Forbidden.