Object moderation layer for Django models
Project description
django-oml
OML means Object Moderation Layer — a mixin model that lets you add content moderation (pending / accepted / rejected states) to any Django model.
Installation
pip install django-oml
Add 'oml' to INSTALLED_APPS and run migrate.
Configuration
Add an OML_CONFIG dictionary to your Django settings:
OML_CONFIG = {
# Set True to let certain groups bypass moderation
'OML_EXCLUDE_MODERATED': True,
# List of group IDs that skip the moderation queue
'OML_EXCLUDED_GROUPS': [],
}
Usage
Inherit from ModeratedModel:
from oml.models import ModeratedModel
class Article(ModeratedModel):
title = models.CharField(max_length=200)
The model gains:
statusfield ('p'pending /'a'accepted /'r'rejected)authorized_byFK to the user who last moderated the objectstatus_dateDateTimeField of the last moderation action.objects.accepted(),.pending(),.rejected()queryset shortcuts.accept(user)and.reject(user)methods
Admin integration
Use ModelAdminOml to get moderation features out of the box:
from oml.admin import ModelAdminOml
@admin.register(Article)
class ArticleAdmin(ModelAdminOml):
pass
This gives you automatically:
status,authorized_by, andstatus_datecolumns in the changelist- A Status filter in the sidebar
- Accept selected and Reject selected bulk actions
rejecton a pending object with no prior accepted state will delete the object. The bulk action shows a warning with the count of deleted objects.
Moderation panel
A cross-model panel that lists all pending items across every ModeratedModel subclass in your project.
- Include the OML URLs in your project's
urls.py:
from django.urls import include, path
urlpatterns = [
...
path('admin/oml/', include('oml.urls')),
]
- Visit
/admin/oml/moderation/. The panel is restricted to staff users.
The panel supports:
- Filtering by content type via
?ct_filter=<model_name> - Per-item Approve / Edit / Reject actions
- Bulk approve via checkbox selection
- Pagination (50 items per page)
Template tag
The panel is rendered via an inclusion tag you can embed in your own templates:
{% load oml_tags %}
{% get_content_for_approval request %}
This renders admin/oml/pending_content.html, which you can override in your project's template directory.
Running the tests
pip install pytest pytest-django
pytest
Compatibility
- Python 3.10, 3.11, 3.12, 3.13, 3.14
- Django 4.2 (LTS), 5.1, 5.2 (LTS), 6.0
Why did we revamp this?
The original django-oml was written in 2013 and last released in 2015. It was archived on GitHub in 2023 with no forks and no active successors.
The codebase still worked conceptually, but it had accumulated a decade of bit-rot: Python 2-only idioms (ugettext_lazy, __unicode__, MIDDLEWARE_CLASSES), missing on_delete arguments that Django 2.0 made mandatory, a silent bug in the group-exclusion logic that made the feature completely non-functional, and a test suite built on abandoned tools (nose, django-nose). None of it would import cleanly on a modern Django project.
Rather than throw it away and start over — or accept that content moderation simply has no maintained, lightweight option in the Django ecosystem — we chose to modernize it in place. The logic was sound; it just needed to catch up with ten years of Django evolution.
Alternatives
These are the other packages that cover similar ground. We looked at all of them before deciding to revamp django-oml.
| Package | Last release | Status |
|---|---|---|
django-moderation |
April 2022 | Unmaintained. Supports up to Django 3.2. |
django-moderation-model-mixin |
November 2021 | Unmaintained. No Django 4+ support. |
django-gatekeeper |
2009 | Abandoned. |
As of June 2026, no actively maintained package provides a simple mixin-based moderation layer compatible with Django 4.2+. django-oml 0.1.0 fills that gap. Django 6.1 support will be added once it reaches a stable release.
Project details
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 django_oml-0.1.3.tar.gz.
File metadata
- Download URL: django_oml-0.1.3.tar.gz
- Upload date:
- Size: 14.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.25 {"installer":{"name":"uv","version":"0.11.25","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Arch Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4118e0b734ff7afab2cedcbd59a4ff63ba4bb8ef972811e74e8942638add10eb
|
|
| MD5 |
9099909a4f16e4d7a8e95998f6e39e86
|
|
| BLAKE2b-256 |
6fe5ee5f3b686692b02ee29a40bcc41cc227f8cde40556758718c9ae0f6464ca
|
File details
Details for the file django_oml-0.1.3-py3-none-any.whl.
File metadata
- Download URL: django_oml-0.1.3-py3-none-any.whl
- Upload date:
- Size: 16.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.25 {"installer":{"name":"uv","version":"0.11.25","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Arch Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9adb75573378b59c94f81d741d0f2da23e07616211f18cc0d9a1b74aa4eb144a
|
|
| MD5 |
ff7d2d810a50695878dfcd3293dc01b9
|
|
| BLAKE2b-256 |
458b7988fd7bc2e72da7f3f41e3fe9753e153603a03297f33a020410bf24c945
|