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 ID

  • descendant_of: Filter to include all descendants of the page with this ID

  • translation_of: Filter to only include translations of the page with this ID

  • fields: Comma-separated list of fields to include in response

  • order: Ordering field (prefix with - for descending)

  • slug: Filter by slug (exact match)

  • show_in_menus: Filter pages shown in menus

  • search: Full-text search (note: when using use_post_filter=true, this uses Django Cast’s enhanced search)

  • limit: Number of results per page

  • offset: Number of results to skip

Django Cast custom filters (requires use_post_filter=true):

  • use_post_filter: Set to true to enable Django Cast’s enhanced filtering

  • date_facets: Filter by year-month (format: YYYY-MM)

  • category_facets: Filter by category slug

  • tag_facets: Filter by tag slug

  • date_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_date for 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}
        ]
    }
}

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.

Comment Moderation

Export training data for spam filter:

GET /api/comment_training_data/

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.

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: Success

  • 201 Created: Resource created

  • 400 Bad Request: Invalid request data

  • 401 Unauthorized: Authentication required

  • 403 Forbidden: Permission denied

  • 404 Not Found: Resource not found

  • 500 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:

  1. Using the Wagtail Pages API to fetch content

  2. Implementing a frontend application (React, Vue, etc.)

  3. 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,date

  • Implement 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