Skip to main content

django-no

https://badge.fury.io/py/django-no.svg https://img.shields.io/pypi/pyversions/django-no.svg https://img.shields.io/pypi/djversions/django-no.svg https://github.com/bashu/django-no/actions/workflows/test.yml/badge.svg

Reusable django app that gives you a reason to say no. Reasons come from a bundled list or from a remote No-as-a-Service (NaaS) API, and can be rendered in templates or fetched from Python code.

Authored by Basil Shubin, and some great contributors.

Installation

First install the module, preferably in a virtual environment. It can be installed from PyPI:

pip install django-no

Requires Python 3.10+ and Django 5.2+.

Setup

You’ll need to add no to INSTALLED_APPS in your project’s settings.py file:

INSTALLED_APPS += [
    "no",
]

There are no models, so no migrations are needed.

Usage

Load the no template tag library and use the {% no %} tag:

{% load no %}

<blockquote>{% no %}</blockquote>

Or store the reason in a variable:

{% load no %}

{% no as reason %}
<p title="{{ reason }}">No.</p>

Every {% no %} picks a new reason. Reasons are auto-escaped like any other template output.

From Python code:

from no import get_reason

get_reason()  # "I'm on a strict 'no commitments' diet."

Configuration

Everything is optional. Without any configuration reasons are picked at random from the bundled list. To change that, set NO in your settings.py:

NO = {
    "BACKEND": "no.backends.local.LocalBackend",
    "OPTIONS": {},
}

BACKEND is the dotted path to a backend class and OPTIONS is passed to it as keyword arguments.

LocalBackend

The default. Picks a random reason from a JSON file containing a list of strings.

path

Path to your own reasons file. Defaults to the bundled reasons.json.

NO = {
    "BACKEND": "no.backends.local.LocalBackend",
    "OPTIONS": {"path": BASE_DIR / "reasons.json"},
}

RemoteBackend

Fetches a reason from an HTTP API that responds with {"reason": "..."}. Whenever the request fails it falls back to LocalBackend and stops calling the API for cooldown seconds.

url

API endpoint, must be http or https. Defaults to https://naas.isalman.dev/no.

timeout

Request timeout in seconds. Defaults to 3.

cooldown

Seconds to wait before retrying the API after a failure. Defaults to 60.

path

Reasons file for the fallback LocalBackend.

NO = {
    "BACKEND": "no.backends.remote.RemoteBackend",
    "OPTIONS": {"timeout": 1, "cooldown": 300},
}

Keep in mind the request is made while the template renders, so a slow API slows down your page by up to timeout seconds.

Custom backends

Subclass no.backends.base.BaseBackend and implement get_reason(). OPTIONS are available as self.options:

from no.backends.base import BaseBackend

class PoliteBackend(BaseBackend):
    def get_reason(self):
        return self.options.get("reason", "No, thank you.")

Example

Please see the example application. This application is used to manually test the functionalities of this package. This also serves as a good example.

Contributing

If you’ve found a bug, implemented a feature or have a good reason to say no and think it is useful then please consider contributing. Patches, pull requests or just suggestions are welcome!

License

django-no is released under the MIT license.

Changes

1.0.0 (2026-09-25)

  • Initial release

Release files for django-no 1.0.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-no 1.0.0
File Size Uploaded
django_no-1.0.0.tar.gz 31.0 kB Details

Built distribution (wheel)

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

Total release size: 61.4 kB

Release files / django_no-1.0.0.tar.gz

Download URL django_no-1.0.0.tar.gz
Size 31.0 kB
Tags Source
SHA-256 checksum
How to use checksums
81b74a3a663d9984a6623076f432b5bd00573f49afee50dfd09881cf9458a192
BLAKE2b-256 checksum
How to use checksums
7209dba7c393099bb60bd729d10ab52dc7e7538e028e8dc2149b0457e8e2178a
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 Sep 25, 2026.

Transparency log

Release files / django_no-1.0.0-py3-none-any.whl

Download URL django_no-1.0.0-py3-none-any.whl
Size 30.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c35c8463e3205078c6c763ec454536d50cfdc5354866fa6b9e5db0417f5c6b5d
BLAKE2b-256 checksum
How to use checksums
2cd1f289d7b4cbf37c30b402c485f37a102f5df09e485655e3b4f1b66e194bdb
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 Sep 25, 2026.

Transparency log

Release history Release notifications | RSS feed

1.1.1

2 release files

1.1.0

2 release files

This release

1.0.0 This release

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