Narito Blog

Django、メンテナンスモードを導入する(django-maintenance-mode)

- PythonDjangoDjangoライブラリ

概要

django-maintenance-modeを使い、Djangoプロジェクトにメンテナンスモードを導入していきます。

Webサイトの大規模な更新等で、Webページを一時的に非表示にしたいというケースがあります。

また、急な不具合が発生した際に原因解明までの繋ぎとして使うとか、小規模なウェブサイトによくありますが、サーバー上のソースを直接編集しているようなケースでも役に立ちます。

今回は、通常は次のように表示されるウェブページがあり... これが普通のページ

メンテナンスモードをオンにすると、次のようにお知らせが表示されます。 メンテナンス中なのを教えてくれる

お知らせがあるので、ユーザーにとっても分かりやすいでしょう。また、503というHTTPステータスコードで返してくれるので、SEO的な都合にも配慮してくれます。

準備

まず、pipでインストールしましょう。

pip install django-maintenance-mode

settings.pyINSTALLED_APPSに足します。

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'maintenance_mode',  # これ
    'app.apps.AppConfig',  # 自作のDjangoアプリ
]

settings.pyMIDDLEWAREに追加します。

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'maintenance_mode.middleware.MaintenanceModeMiddleware'  # これ
]

503.htmlを作成しましょう。デフォルトではtemplates直下の503.htmlが読まれます。

CSSフレームワークBlumaを使った、シンプルなページです。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>サイトメンテナンス中 - naritoブログ</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css">
    <script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
</head>
<body>
    <section class="section">
        <div class="container">
            <h1 class="title">サイトのメンテナンス中です...</h1>
            <span class="icon has-text-info is-large">
                <i class="fas fa-wrench fa-3x fa-spin"></i>
            </span>
        </div>
    </section>
</body>
</html>

メンテナンスモードの開始と終了

URLにアクセス

あるURLにアクセスするとメンテナンスモードがオンになるという方法です。そのためのURLをdjango-maintenance-mode側で提供しています。

この方法の注意点として、スーパーユーザーのみがON/OFF切り替え可能なことです。他のユーザー、例えばis_staffがTrueなユーザーでも切り替えれるようにしたいならば、専用のビューを作りましょう。

urls.pyに追記しまして...

path('maintenance-mode/', include('maintenance_mode.urls')),

これにより、/maintenance-mode/on/にアクセスするとメンテナンスモードになり、/maintenance-mode/off/でオフにできます。

コマンド

以下のコマンドで、切り替えることもできます。

python manage.py maintenance_mode on
python manage.py maintenance_mode off

関数

set_maintenance_mode()という関数が提供されており、それで切り替えることもできます。

from maintenance_mode.core import set_maintenance_mode
set_maintenance_mode(True)
set_maintenance_mode(False)

また、get_maintenance_mode()関数で今がメンテナンス中かどうかを判断することもできます。

from maintenance_mode.core import get_maintenance_mode

# メンテナンス中ならば
if get_maintenance_mode():
    ...

後述の、メンテナンス中でも一部ユーザーはページを見れるようにする方法と組み合わせれば、スタッフ権限のユーザーでも切り替えできるビューを作ることもできます。

メンテナンス中でも一部ユーザーは見れるように

メンテナンスモード中に、一部のユーザー...例えばスーパーユーザーは普通にページアクセスできる、といった機能も欲しいはずです。

まずですが、settings.pyに以下を記述しましょう。メンテナンス中であってもadmin管理サイトが使えるようになります。

# メンテナンス中でも管理サイトは使えるように。
MAINTENANCE_MODE_IGNORE_ADMIN_SITE = True

更に、ログインしたユーザーは通常のページも見れるようにしたいなら次の指定をします。

# ログインユーザーは、メンテナンス中でも通常ページが見れる。
MAINTENANCE_MODE_IGNORE_AUTHENTICATED_USER = True

他にもいくつかあり、is_staff権限やis_superuser権限のユーザーに対する設定もあります。

# is_staffなユーザーはメンテナンス中でも通常ページが見れる。
MAINTENANCE_MODE_IGNORE_STAFF = True

# is_superuserなユーザーはメンテナンス中でも通常ページが見れる。
MAINTENANCE_MODE_IGNORE_SUPERUSER = True

切り替えを簡単にできるようにする

ナビバー等にリンクを用意し、ワンクリックで切り替えれるようにすると扱いやすいです。

そのためには、まずsettings.pycontext_processorsに追加します。

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')]
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
                'maintenance_mode.context_processors.maintenance_mode',  # これ
            ],
        },
    },
]

後は、テンプレートに次のような記述をしておきましょう。

    {% if user.is_superuser %}
        {% if maintenance_mode %}
            <a href="{% url 'maintenance_mode_off' %}">メンテナンス終了</a>
        {% else %}
            <a href="{% url 'maintenance_mode_on' %}">メンテナンス開始</a>
        {% endif %}
    {% endif %}

公式サイト

django-maintenance-mode