Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

Django Headless

PyPI version Python versions Django versions License

With Django Headless you quickly create a REST API for your models, making it easy to turn Django into a powerful headless CMS.

✨ Features

  • 🎯 Easy configuration: Add @expose decorator to any model and get instant REST endpoints
  • 🤝 Plays nice: Seamlessly integrates with existing Django applications
  • 💈 Supports singletons: Special handling for singleton models (settings, configurations, etc.)
  • 🔍 Flexible filtering: Optional filtering backend based on Django ORM lookups
  • 🛡️ Secure: Inherits Django's security features and permissions system

🚀 Quick Start

Installation

☝️ Django Headless depends on Django and Django Rest Framework.

pip install django-headless

Add to Django Settings

# settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'headless',  # Add this
    # ... your apps
]

REST_FRAMEWORK = {
    # Optional: add the lookup filter backend
    "DEFAULT_FILTER_BACKENDS": [
        "headless.rest.filters.LookupFilter",
    #...
    # Optional: add the secret key authentication class
    "DEFAULT_AUTHENTICATION_CLASSES": [
        "headless.rest.authentication.SecretKeyAuthentication",
    #... other DRF config
}

Create Your First Headless 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

Add URLs

# urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('headless.urls')),
]

That's it! 🎉 Your model is now available via REST API at /api/blog.blogpost/

📖 Usage Examples

Basic Model Registration

# apps/blog/models.py
from django.db import models
from headless import expose


@expose()
class Article(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    author = models.ForeignKey("user.User", on_delete=models.CASCADE)

Generated endpoints:

  • GET /api/blog.article/ - List all articles
  • POST /api/blog.article/ - Create new article
  • GET /api/blog.article/{id}/ - Retrieve specific article
  • PUT /api/blog.article/{id}/ - Update article
  • PATCH /api/blog.article/{id}/ - Partially update article
  • DELETE /api/blog.article/{id}/ - Delete article

Singleton Models

Perfect for site settings, configurations, or any model that should have only one instance:

# apps/config/models.py
from django.db import models
from headless import expose


@expose(singleton=True)
class SiteConfiguration(models.Model):
    site_name = models.CharField(max_length=100)
    maintenance_mode = models.BooleanField(default=False)
    contact_email = models.EmailField()
    
    class Meta:
        verbose_name = "Site Configuration"

Generated endpoints:

  • GET /api/config.siteconfiguration/ - Get configuration
  • PUT /api/config.siteconfiguration/ - Update configuration
  • PATCH /api/config.siteconfiguration/ - Partial update

Advanced Filtering

Django Headless supports Django ORM lookups for powerful filtering. Add the LookupFilter backend to your default filter backends:

REST_FRAMEWORK = {
    "DEFAULT_FILTER_BACKENDS": [
        "headless.rest.filters.LookupFilter",
    #... other DRF config
}

Filter examples:

# Basic filtering
GET /api/blog.blogpost/?published=true

# Field lookups
GET /api/blog.blogpost/?title__icontains=django
GET /api/blog.blogpost/?created_at__gte=2023-01-01
GET /api/blog.blogpost/?author__username=john

# Multiple filters
GET /api/blog.blogpost/?published=true&created_at__year=2023

Values are automatically cast based on the field type. Booleans can be represented as true, 1 or on (and false, 0 or off). Multi-value lookups can be comma-separated (e.g. id__in=1,2,3).

Field Expansion & Model Properties (optional)

By default, endpoints use a plain ModelSerializer. To enable ?expand= for related models and automatic exposure of model properties as read-only fields, point DEFAULT_SERIALIZER_CLASS at the FlexibleSerializer:

HEADLESS = {
    "DEFAULT_SERIALIZER_CLASS": "headless.rest.serializers.FlexibleSerializer",
}
# Return the related author inline
GET /api/blog.article/?expand=author

# Return the articles of a category inline
GET /api/blog.category/1/?expand=articles

Only relations to other exposed models are expandable.

🎛️ Configuration Options

The @expose decorator accepts the following configuration options:

Option Type Default Description
singleton bool False Creates singleton endpoints (no create, list and delete endpoints)
search_fields List[str] All the model's CharFields Allows you to overwrite the allowed search fields.

Global Settings

# settings.py
HEADLESS =  {
    # True always shows the boot log, False never does.
    # The default (None) shows it automatically in server mode.
    "BOOT_LOG": None,
    "AUTH_SECRET_KEY": None,
    "AUTH_SECRET_KEY_HEADER": "X-Secret-Key",
    "DEFAULT_SERIALIZER_CLASS": "rest_framework.serializers.ModelSerializer",
    "FILTER_EXCLUSION_SYMBOL": "~",
    "FILTER_TRUE_VALUES": ["true", "1", "on"],
    "FILTER_FALSE_VALUES": ["false", "0", "off"],
    "FILTER_NULL_VALUES": ["null", "none", "empty"],
    "NON_FILTER_FIELDS": [
        "search",
        "limit",
        "page",
        "fields",
        "omit",
        "expand",
        "ordering"
    ],

}

🛠️ Requirements

  • Python 3.12+
  • Django 5.0+
  • Django REST Framework 3.16+

🤝 Contributing

We welcome contributions! Here's how to get started:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Add tests for your changes
  5. Run the test suite (python manage.py test)
  6. Commit your changes (git commit -m 'Add amazing feature')
  7. Push to the branch (git push origin feature/amazing-feature)
  8. Open a Pull Request

Development Setup

# Clone the repository
git clone https://github.com/dwarsbit/django-headless.git
cd django-headless

# Create virtual environment
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

# Install dependencies
poetry install

# Run tests
poetry run test

# Run example project
cd example_project
python manage.py migrate
python manage.py runserver

📚 Documentation

For detailed documentation, visit djangoheadless.org

🐛 Issues & Support

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙏 Acknowledgments

  • Built on the shoulders of Django and Django REST Framework
  • Inspired by the headless CMS and Jamstack movement
  • Thanks to all contributors and the Django community

Made in Europe 🇪🇺 with 💚 for Django

Metadata

Release files for django-headless 1.0.0rc4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-headless 1.0.0rc4
File Size Uploaded
django_headless-1.0.0rc4.tar.gz 19.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for django-headless 1.0.0rc4
File Interpreter ABI Platform
django_headless-1.0.0rc4-py3-none-any.whl Python 3 none any Details

Total release size: 43.8 kB

Release files / django_headless-1.0.0rc4.tar.gz

Download URL django_headless-1.0.0rc4.tar.gz
Size 19.6 kB
Tags Source
SHA-256 checksum
How to use checksums
dc93270e2e8f91228058c89bbb718e3bea58ff5665fd1e612f68ef0440ba8317
BLAKE2b-256 checksum
How to use checksums
f92c4380146af03a93221119e1e7b7891aea5e2ba41d7a4124167343deb2b7ea
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.4.1 CPython/3.14.7 Darwin/27.0.0

Release files / django_headless-1.0.0rc4-py3-none-any.whl

Download URL django_headless-1.0.0rc4-py3-none-any.whl
Size 24.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
db1969a9ca36cf03d5d8b4e992238c9cae7044e16df370192f511d47fc0e5ae9
BLAKE2b-256 checksum
How to use checksums
9a6f07b65008226629f6237c833166c4dbe5f944491f8f0821ca2b5516f130dc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.4.1 CPython/3.14.7 Darwin/27.0.0
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page