Skip to main content
django-oml

django-oml

CI Coverage

OML means Object Moderation Layer — a mixin model that lets you add content moderation (pending / accepted / rejected states) to any Django model.

Example app

A runnable blog demo with Article and Comment as moderated models is available at github.com/angvp/oml-example.

Installation

pip install django-oml

Add 'oml' to INSTALLED_APPS before django.contrib.admin and run migrate:

INSTALLED_APPS = [
    'oml',  # before django.contrib.admin
    'django.contrib.admin',
    ...
]

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:

  • status field ('p' pending / 'a' accepted / 'r' rejected)
  • authorized_by FK to the user who last moderated the object
  • status_date DateTimeField 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, and status_date columns in the changelist
  • A Status filter in the sidebar
  • Accept selected and Reject selected bulk actions

reject on 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.

  1. Include the OML URLs in your project's urls.py:
from django.urls import include, path

urlpatterns = [
    ...
    path('admin/oml/', include('oml.urls')),
]
  1. 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.

Metadata

Release files for django-oml 0.1.4

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-oml 0.1.4
File Size Uploaded Provenance Actions
django_oml-0.1.4.tar.gz 15.0 kB Without provenance Details for django_oml-0.1.4.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for django-oml 0.1.4
File Interpreter ABI Platform Actions
django_oml-0.1.4-py3-none-any.whl Python 3 none any Details for django_oml-0.1.4-py3-none-any.whl

Total release size: 32.6 kB

Release files / django_oml-0.1.4.tar.gz

Download URL django_oml-0.1.4.tar.gz
Size 15.0 kB
Tags Source
SHA-256 checksum
How to use checksums
88ff1c9d7dfa3f40a1c71c2264c177b298dd21cfbdbd09e658dc0515a1457514
BLAKE2b-256 checksum
How to use checksums
cad7d83acfca4fcf32d8e47e4c09a7ef415fe4b2516a112c74f9f435167862a0
Upload date
Uploaded using Trusted Publishing?
What is 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}

Release files / django_oml-0.1.4-py3-none-any.whl

Download URL django_oml-0.1.4-py3-none-any.whl
Size 17.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a853fc591884018502b6786bb9adea6c0479c42bd778305abbb59bc6c49ad4be
BLAKE2b-256 checksum
How to use checksums
bf815c69e1902b2e2861f681795c11e8826b4f8d7ab8162fe91ccbf9609a1e1c
Upload date
Uploaded using Trusted Publishing?
What is 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}

Security for django-oml 0.1.4

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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