Skip to main content

django-maker-checker

CI Coverage PyPI Python Docs License: MIT

Not every change should take effect immediately.

django-maker-checker is an open-source, headless maker-checker (four-eyes) approval engine for Django. It lets you require a second authorized person to approve sensitive changes before they take effect.

In financial and enterprise systems, a user might need to change a credit limit, create a privileged user, modify account details, or initiate another sensitive operation. You need more than an approval button: you need enforceable separation of duties, configurable policies, controlled execution and an audit trail.

django-maker-checker provides reusable infrastructure for these controls, so you don't have to build a separate approval mechanism for every Django application.

Why django-maker-checker?

  • Changes are held until approval. A guarded action becomes an approval request rather than taking effect immediately. On approval, the action executes against the current state of the data; if that state has changed, the request fails instead of silently overwriting newer changes.
  • Separation of duties is enforced. The maker cannot approve their own request, including through privileged-user or delegation paths. A person cannot approve multiple steps of the same request and a request cannot be raised if no eligible checker exists.
  • Approval rules are data, not code. Configure which actions require approval, who can approve them and how approval steps work without deploying code for every policy change. Policy changes are versioned with who made them, when, and why.
  • Approvals have operational controls. Configure SLAs, reminders, and escalation to backup approvers so pending requests don't depend entirely on someone remembering to check a queue.
  • Decisions are auditable. Requests have a timeline, decisions are recorded, and events can be passed to your audit log.
  • Concurrent decisions are controlled. Decisions lock the relevant row and only one open request may exist per item, subject to the database requirements below.
  • Your UI stays yours. The library provides models, rules, services, and read queries without imposing a frontend or admin interface.

Who is it for?

django-maker-checker is designed for Django applications where sensitive operations need an independent approval step.

Use case Example
Fintech and financial systems Changing credit limits or payment instructions
User administration Creating or deleting privileged users
Accounting and back-office systems Approving sensitive account or configuration changes
Multi-tenant SaaS Letting each tenant define its own approval policies
Enterprise applications Requiring independent authorization for sensitive operations

These are examples of workflows the library can help implement; each action must still be integrated and configured by the application.

How it works

The typical lifecycle is straightforward:

  1. Define an action. Mark a sensitive operation as requiring approval when its policy says so.
  2. Submit a request. A maker initiates the action. Instead of applying the change immediately, the library creates an approval request.
  3. Evaluate the policy. The request is routed to eligible checkers according to the configured rules.
  4. Review the request. A checker can approve, reject, or request changes, depending on the workflow.
  5. Apply the change. Once the approval requirements are satisfied, the action executes against the current data state.
  6. Record the outcome. The request's decisions and events remain available for auditing.

The approval engine handles the workflow; your application remains responsible for defining the business operation and building the user experience.

How it compares

Capability django-maker-checker Workflow engines (e.g. django-approval-workflow) Moderation libraries (e.g. django-approval)
Primary purpose Approval-gated execution of sensitive actions Orchestrating workflows across steps Reviewing proposed object edits
Approval policy Tenant-configurable rules Typically defined per workflow Typically defined per model or workflow
Separation of duties Enforced by the approval engine Depends on workflow configuration Depends on implementation and permissions
SLAs and escalation Built in May require additional scheduling and escalation logic Depends on the library
Multi-tenancy Supported through configurable integration points Depends on the engine Depends on the library
User interface Headless Depends on the engine Depends on the library

Choose a broader workflow engine if you need complex orchestration, such as parallel branches, organizational hierarchies, or rich process routing.

Choose django-maker-checker when your primary requirement is to ensure that sensitive changes cannot be made by one person acting alone, with approval rules and decisions that can be audited.

Requirements

  • Python 3.11+
  • Django 5.2, 6.0, or 6.1
  • django.contrib.auth and django.contrib.contenttypes
  • django-fsm-2, installed automatically

Database: PostgreSQL is recommended for production. SQLite works for development and tests. On MySQL/MariaDB, the guarantee that only one open request exists per item is not enforced because these databases ignore Django's conditional unique constraints.

Background jobs: Celery is optional. It can run the SLA job; alternatively, schedule the relevant management command with cron.

Install the Celery integration with:

pip install "django-maker-checker[celery]"

Quick start

1. Install the package

pip install django-maker-checker

2. Add it to Django

A single-tenant project using Django's built-in users, groups, and permissions requires no additional integration configuration.

# settings.py

INSTALLED_APPS = [
    # ...
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django_maker_checker",
]

3. Define an approval-gated action

Suppose you want credit-limit changes to require approval.

from django_maker_checker.actions import approval_action


@approval_action(
    "credit_limit_change",
    label="Credit Limit Change",
    category="Accounts",
    lock_key=lambda p: f"account:{p['account_id']}",
)
def change_credit_limit(
    *,
    tenant,
    maker,
    context,
    account_id,
    new_limit,
):
    Account.objects.filter(pk=account_id).update(
        credit_limit=new_limit
    )

The lock_key identifies the account associated with the request, allowing the library to prevent multiple open requests for the same item when the database supports the required constraint.

Register the action from your application's AppConfig.ready().

4. Configure an approval policy

Run the migrations:

python manage.py migrate

The migrations also create the permission approvals.approve_credit_limit_change. Grant it to the appropriate group, then configure the policy to use that group.

from django_maker_checker import policies, services
from django_maker_checker.constants import Decision
from django_maker_checker.models import Tenant


policies.save_policy(
    policies.policy_for(
        Tenant.default(),
        "credit_limit_change",
    ),
    policies.PolicySpec(
        approvers=[f"r:{risk_officers.pk}"],
    ),
    by=admin_user,
)

5. Submit and approve a request

When a maker initiates the action, the change is held pending approval.

outcome = change_credit_limit(
    tenant=Tenant.default(),
    maker=request.user,
    justification="Annual review",
    account_id=42,
    new_limit="5000.00",
)

assert outcome.pending  # The credit limit has not changed yet.

An eligible checker can approve the request:

services.decide(
    outcome.approval_request.pk,
    risk_officer,
    Decision.APPROVE,
    "Within appetite",
)

Once the approval requirements are satisfied, the action executes and the resulting change is recorded.

The same workflow supports rejection with a reason and requesting changes from the maker.

Note: This example illustrates the core API. Your application must supply its own Account model, user and group setup, action registration, and approval interface.

Configurable approval workflows

Approval policies can express different requirements, including:

  • A single approver.
  • Any N of several eligible approvers.
  • Approval from all required approvers.
  • Ordered approval steps.
  • SLAs, reminders and escalation to backup approvers.

Policies are stored as data, allowing authorized administrators to adjust approval requirements without deploying application code for every policy change.

Integrating with your application

The library is headless by design. It doesn't force you to use a particular frontend, admin interface, or API framework.

For multi-tenant applications or projects with custom roles and permissions, configure the relevant integration points:

  • APPROVALS_TENANT_MODEL
  • APPROVALS_ROLE_MODEL
  • APPROVALS_ADAPTER

See the integration guide.

Documentation

Full documentation: https://django-maker-checker.readthedocs.io

Contributing

Contributions are welcome! Whether you're improving the API, reporting edge cases, adding integrations, or strengthening the test suite, your input is valuable.

  • Read CONTRIBUTING.md for contribution guidelines.
  • Follow the development guide to set up your environment.
  • Start with tests/README.md, which describes the test suite and how it specifies expected library behaviour.
  • Open an issue to discuss substantial changes before submitting a pull request.

Bug reports, use cases, design feedback, and pull requests are all appreciated.

License

Released under the MIT License.

Metadata

Release files for django-maker-checker 0.8.0

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-maker-checker 0.8.0
File Size Uploaded
django_maker_checker-0.8.0.tar.gz 82.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for django-maker-checker 0.8.0
File Interpreter ABI Platform
django_maker_checker-0.8.0-py3-none-any.whl Python 3 none any Details

Total release size: 153.1 kB

Release files / django_maker_checker-0.8.0.tar.gz

Download URL django_maker_checker-0.8.0.tar.gz
Size 82.6 kB
Tags Source
SHA-256 checksum
How to use checksums
0c6080d39d80d6ed13c1cecda61a13895227092f411e3cc9f16b80773ffce400
BLAKE2b-256 checksum
How to use checksums
bb439cab9b3c42f9ce5f7135b044214ced369fd20e41fa9d1c9dc1d127614fdf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

Release files / django_maker_checker-0.8.0-py3-none-any.whl

Download URL django_maker_checker-0.8.0-py3-none-any.whl
Size 70.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c643c8517fc136daa30a7db3153028d5d8ef587ba1396db3b193bcfefcd3d266
BLAKE2b-256 checksum
How to use checksums
173639a8373fe93576b5db163370948b72abc73ed1de8f356a8e61f2825c8c16
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.8.0 This release

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

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