Skip to content

Quickstart

Three minutes from a configured project to a site that announces, closes and reopens itself. This page assumes you have finished Installation.

Schedule a window from the command line

$ ./manage.py start_countdown \
      --banner +2m \
      --service +5m \
      --message "Database upgrade" \
      --noinput

About to create / replace countdown:
  Site:              example.com (id=1)
  Banner shows now → 2026-08-05 10:02:00 CEST
  Service mode ends: 2026-08-05 10:07:00 CEST
  Message:           Database upgrade

✓ Created countdown for example.com.

Read the two durations like this:

  • --banner +2m — the banner is visible from now, and the site closes in two minutes.
  • --service +5m — service mode lasts five minutes counted from the moment the site closes, not from now. The site reopens at +7m.

Reload the page

The banner appears on the next request. Nothing is pushed to open browser tabs — refresh to see it.

Run the command with no arguments for an interactive version that prompts for each value with sensible defaults.

Or create it in the admin

Django admin → Site shutdown countdownsAdd:

Field Meaning
Site Which domain this countdown closes
Countdown time When the site starts returning 503
Maintenance end When it reopens — leave empty for indefinite
Short message Banner headline, max 200 characters
Long description Optional paragraph shown on the maintenance page

See Django admin for the gotchas around editing a countdown that has already expired.

What you will see

timeline
    title A +2m / +5m window
    now : Banner appears for everyone
    +2m : Site returns 503 for the public
        : Superusers keep browsing, with a maintenance banner
    +7m : Site reopens automatically for everyone

Concretely:

  1. Before the cutoff — every visitor sees the countdown banner with a live timer and the estimated duration of the upcoming maintenance.
  2. During the window — anonymous and non-superuser visitors get the maintenance page with HTTP 503; the page shows its own timer counting down to reopening, and takes them back the moment the site returns. Superusers browse normally and see a subdued "system under maintenance" banner instead.
  3. After maintenance_until — the middleware stops blocking, and the banner disappears for everyone. The database row stays behind until you delete it.

For the full state table, see How it works.

Close the site indefinitely

Leave the end open when you cannot predict how long the work will take:

$ ./manage.py start_countdown --banner +1m --service indefinite --noinput
✓ Created countdown for example.com.
  ⚠  Indefinite mode — the site will not reopen on its own. Run `manage.py stop_countdown` to unblock it.

Nothing reopens the site on its own in this mode. The maintenance page tells visitors there is no scheduled end and keeps checking the server in the background, so it takes them back within seconds of you unblocking it.

Reopen the site

Deleting the countdown row is the universal "unblock now" action, whatever state the window is in:

$ ./manage.py stop_countdown --noinput
About to remove 1 countdown(s):
  example.com  [banner showing]  2026-08-05 03:50:49 CDT  — Emergency maintenance

✓ Removed 1 countdown(s).
  example.com — unblocked

It always lists what it is about to remove, and asks first unless you pass --noinput. Add --site-id N on a multi-tenant install; without it every site's countdown goes.

Site shutdown countdowns → select the row → Delete selected.

The admin stays reachable while the site is blocked, so this works even when you cannot get a shell.

Editing an expired countdown fails validation in the admin

SiteCountdown.clean() rejects any countdown_time in the past, so once a window has opened you cannot save the form again from the admin — even to push the end time out.

Use the command instead; it validates against explicit guards rather than the model form:

$ ./manage.py extend_countdown --service +30m

Try it without touching your project

The repository ships a runnable demo project:

$ git clone https://github.com/iplweb/django-countdown.git
$ cd django-countdown
$ uv sync --all-extras
$ cd example
$ uv run python manage.py migrate
$ uv run python manage.py createsuperuser
$ uv run python manage.py runserver