🚀 Installation
Requirements
- Python 3.12+
- Django 5.0+ (including 6.x)
- Django REST Framework 3.16+
Install
pip install django-headless
Configure Django
Add headless to INSTALLED_APPS:
# settings.py
INSTALLED_APPS = [
# ...
"django.contrib.staticfiles",
"rest_framework",
"headless", # Add this
]
Generated routes require authentication by default and support ORM lookup filtering out of the box. Configure authentication classes (via REST_FRAMEWORK or HEADLESS.DEFAULT_AUTHENTICATION_CLASSES) so requests can authenticate, and pagination if you want paginated lists:
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": [
"rest_framework.authentication.SessionAuthentication",
],
"DEFAULT_PAGINATION_CLASS": "headless.rest.pagination.PageNumberPagination",
"PAGE_SIZE": 25,
}
Generated routes answer 403 for unauthenticated requests because HEADLESS.DEFAULT_PERMISSION_CLASSES defaults to IsAuthenticated. For a public headless CMS, set it to AllowAny — see permissions.
Wire the URLs
# urls.py
from django.urls import path, include
urlpatterns = [
# ...
path("api/", include("headless.rest.urls")),
]
Routes are built automatically when your project starts — for runserver, WSGI/ASGI servers and management commands alike. On start, a boot log shows the exposed models and the number of generated routes.
Expose your first model
# apps/blog/models.py
from django.db import models
from headless import expose
@expose()
class BlogPost(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
published = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
Run python manage.py runserver and your API is live at /api/blog.blogpost 🎉
Project settings
All package-specific configuration lives in a single HEADLESS dict — see the settings reference for every option.