Custom content for django CMS — without the boilerplate.
Building custom content in django CMS by hand means wiring up a grouper, versioning, a grouper admin, frontend editing, an app hook and migrations yourself. djangocms-custom-content does all of that — you write the model.
Write this…
from django.db import models
from djangocms_custom_content.models import AbstractCustomGrouper, AbstractCustomContent
class Article(AbstractCustomGrouper):
pass
class ArticleContent(AbstractCustomContent):
article = models.ForeignKey(Article, on_delete=models.CASCADE)
language = models.CharField(max_length=10)
slug = models.SlugField()
title = models.CharField(max_length=200)
body = models.TextField()
class CMSConfig:
enable_versioning = True
enable_frontend_editing = True
apphook = True
…and that model (plus a few lines of grouper admin) gives you, for free:
per-language draft/publish version history
frontend, double-click editing inside the page
a detail view at a clean URL, with get_absolute_url() injected — swap in your own view or add extra URLs when you outgrow the default
a grouper admin to create and manage content
Want related content? Add one line to the grouper — authors = RelationField("people.Person", ordered=True) — and the admin renders a sortable autocomplete, anchored to the grouper so the link survives every new version.
Why you’ll want it
Write the model, skip the plumbing — versioning, grouper admin, frontend editing, app hooks and migrations are handled.
Relations that survive versioning — related content is anchored to the grouper, so links don’t break when a new version is published.
Sortable related-content widgets, free — every relation renders as an autocomplete multi-select in the admin, drag-sortable when ordered.
Relate to anything without touching it — generic relations need no foreign key or migration on the target model.
Multi-language & versioned — per-language draft/publish history per content model.
Batteries included — complete blog, people, categories and services apps, supported and migrated, to install as-is or read and adapt.
Current django CMS and Django — see the badges above for the supported releases.
See it work in two minutes
Don’t build anything yet — turn on a bundled example and click around first:
pip install djangocms-custom-content[djangocms-versioning]
(Versioning is optional; drop the extra if you don’t want draft/publish history.)
Add the blog (plus the apps it relates to) to INSTALLED_APPS and migrate:
INSTALLED_APPS = [
# ... django CMS and its dependencies ...
"djangocms_custom_content",
"djangocms_custom_content.contrib.people",
"djangocms_custom_content.contrib.categories",
"djangocms_custom_content.contrib.blog",
]
python manage.py migrate
That’s it — a versioned, frontend-editable blog in the admin, with sortable authors and categories relations and ready-to-place CMS plugins, no models written. Then build your own by following the documentation:
Bundled apps
djangocms_custom_content.contrib ships complete, installable applications (models + admin + django CMS plugins). Install and rely on them, or read them as worked examples and adapt — either way their schema changes arrive as migrations that upgrade an existing database:
djangocms_custom_content.contrib.people: Person grouper/content (a versioned grouper without a language field) + “Person teaser” plugin, and an app hook giving every person a detail URL
djangocms_custom_content.contrib.categories: FlatCategory — a grouper-less taxonomy used as a relation target + “Category list” plugin
djangocms_custom_content.contrib.services: a versioned, frontend-editable Service/ServiceContent pair + “Service teaser” and “Featured services” plugins
djangocms_custom_content.contrib.blog: blog posts with ordered authors and categories relations + “Blog post” teaser and a paginated “Blog post list” plugin
To enable one (or more), add the module(s) to INSTALLED_APPS and run migrations:
INSTALLED_APPS = [
...,
'djangocms_custom_content',
'djangocms_custom_content.contrib.people', # each app is optional
'djangocms_custom_content.contrib.services',
'djangocms_custom_content.contrib.categories',
'djangocms_custom_content.contrib.blog',
...,
]
python manage.py migrate
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the BSD-3-Clause License.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file djangocms_custom_content-0.9.0.tar.gz.
File metadata
- Download URL: djangocms_custom_content-0.9.0.tar.gz
- Upload date:
- Size: 124.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9f9f0a297a4910c41bd0561bdde4247c1896a4cf673e934d4c56ad63c457ab5c
|
|
| MD5 |
675363e708fa44cb69828a81f2d5c1e1
|
|
| BLAKE2b-256 |
cf97eba2dee72a74f74baf361d21b6e909e43aeb34629d82a3687d5bf5c93bda
|
Provenance
The following attestation bundles were made for djangocms_custom_content-0.9.0.tar.gz:
Publisher:
publish-to-live-pypi.yml on fsbraun/djangocms-custom-content
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
djangocms_custom_content-0.9.0.tar.gz -
Subject digest:
9f9f0a297a4910c41bd0561bdde4247c1896a4cf673e934d4c56ad63c457ab5c - Sigstore transparency entry: 2618629510
- Sigstore integration time:
-
Permalink:
fsbraun/djangocms-custom-content@140838da688e93f3a08300a69a1715788c18a14d -
Branch / Tag:
refs/tags/0.9.0 - Owner: https://github.com/fsbraun
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-to-live-pypi.yml@140838da688e93f3a08300a69a1715788c18a14d -
Trigger Event:
release
-
Statement type:
File details
Details for the file djangocms_custom_content-0.9.0-py3-none-any.whl.
File metadata
- Download URL: djangocms_custom_content-0.9.0-py3-none-any.whl
- Upload date:
- Size: 73.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3c847ef5856f8429cf77db136fe2e54f741d072c9ca9a44dbb75379a8ed0e7a4
|
|
| MD5 |
74c66517bda5597c5d7903f7e0aa1017
|
|
| BLAKE2b-256 |
ffeebfb89c2b3c67aa4966871f327739f07bc3d73c9eca261faa4afb80904d00
|
Provenance
The following attestation bundles were made for djangocms_custom_content-0.9.0-py3-none-any.whl:
Publisher:
publish-to-live-pypi.yml on fsbraun/djangocms-custom-content
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
djangocms_custom_content-0.9.0-py3-none-any.whl -
Subject digest:
3c847ef5856f8429cf77db136fe2e54f741d072c9ca9a44dbb75379a8ed0e7a4 - Sigstore transparency entry: 2618629556
- Sigstore integration time:
-
Permalink:
fsbraun/djangocms-custom-content@140838da688e93f3a08300a69a1715788c18a14d -
Branch / Tag:
refs/tags/0.9.0 - Owner: https://github.com/fsbraun
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-to-live-pypi.yml@140838da688e93f3a08300a69a1715788c18a14d -
Trigger Event:
release
-
Statement type: