Djangoのキャッシュ機能をHerokuで使う Memcached Cloud編

#本記事のテーマ

Djangoのキャッシュ機能で、HerokuのMemcached Cloudを使うための設定方法を説明します。

というのも、[Heroku Dev Center（Herokuの開発者コミュニティ）](https://devcenter.heroku.com/articles/memcachedcloud#using-memcached-from-python)に記載の通りの設定方法だとエラーになってしまい、初心者のつまづきポイントになりそうなためです。

#環境

- Python 3.7.0
- Django 2.1
- django-bmemcached 0.2.3
- python-binary-memcached 0.28.0

#設定方法

##1. HerokuにMemcached Cloudを導入する

###1.1. コマンドで導入する場合

`heroku addons:create memcachedcloud:30`を実行します。
`30`の部分はサイズ(MB)で、30MBまでは無料です。

```
$ heroku addons:create memcachedcloud:30
Creating memcachedcloud:30 on ⬢ (Herokuアプリ名)... free
Created memcachedcloud-contoured-23352 as MEMCACHEDCLOUD_PASSWORD, MEMCACHEDCLOUD_SERVERS, MEMCACHEDCLOUD_USERNAME
Use heroku addons:docs memcachedcloud to view documentation
```

###1.2. 管理画面で導入する場合

ResoucesタブのAdd-onsから`Memcached Cloud`を検索して選択します。

<img width="750" alt="スクリーンショット 2018-12-14 17.20.01.png" src="https://qiita-image-store.s3.amazonaws.com/0/317369/aed35287-c0ed-8d41-4e39-85a10d99503b.png">

Planについては、30MBであれば無料(Free)です。
Planを選んだら、続いて`Provision`を選択します。

<img width="468" alt="スクリーンショット 2018-12-14 17.21.19.png" src="https://qiita-image-store.s3.amazonaws.com/0/317369/11cd41c4-5faa-23b5-8db9-76e4e82a3682.png">


##2. ローカルの開発環境へdjango-bmemcachedをインストールする

HerokuでMemcachedを使うため、django-bmemcachedをインストールします。

```
(venv) $ pip install django-bmemcached
```

すると、以下のパッケージがインストールされます。

```
(venv) $ pip list
Package                 Version  
----------------------- ---------
（略）
django-bmemcached       0.2.3 # 追加    
python-binary-memcached 0.28.0 # 追加   
typing                  3.6.6 # 追加    
uhashring               1.1 # 追加      
（略）
```

##3. それらパッケージをrequirements.txtに反映させる

```
(venv) $ pip freeze > requirements.txt
```

##4. settings.pyを編集する

###4.1. Heroku用の設定

既にローカルの開発環境でMemcachedを使用中であれば、settings.pyのCACHESは以下のような設定になっているかと思います。

```python:settings.py（変更前）
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': '127.0.0.1:11211',
    }
}
```

これをHeroku用に以下のように変更します。

```python:settings.py（変更後）
import os

# Heroku Dev Centerでは以下の記載があるが、不要
# import urlparse
# import json　

CACHES = {
    'default': {
        'BACKEND': 'django_bmemcached.memcached.BMemcached',
#       'LOCATION': os.environ.get('MEMCACHEDCLOUD_SERVERS').split(','), 
#       と、Heroku Dev Centerでは記載されているが
#       AttributeError: 'NoneType' object has no attribute 'split'
#       のエラーになるため、以下のように記述する。LOCATIONはリスト形式で設定すれば良い。
        'LOCATION': [os.environ.get('MEMCACHEDCLOUD_SERVERS')],
        'OPTIONS': {
            'username': os.environ.get('MEMCACHEDCLOUD_USERNAME'),
            'password': os.environ.get('MEMCACHEDCLOUD_PASSWORD')
        }
    }
}
```

なお、`MEMCACHEDCLOUD_SERVERS`, `MEMCACHEDCLOUD_USERNAME`, `MEMCACHEDCLOUD_PASSWORD`といった環境変数は、さきほどMemcached Cloudを導入した時点でHerokuに設定済みとなっています。

`heroku config`コマンドか、Herokuの管理画面の`settingsタブ > Reveal Config Vars`を選択することで確認できます。

###4.2. ローカルの開発環境用の設定

ローカルの開発環境のDjangoの設定を、もし以下のようにlocal_settings.pyで管理しているのであれば・・・

```python:settings.py
try:
    from .local_settings import *
except ImportError:
    pass
```

local_settings.pyに以下を追記します。

```python:local_settings.py（変更後）
CACHES = {
    'default': {
        'BACKEND': 'django_bmemcached.memcached.BMemcached',
        'LOCATION': '127.0.0.1:11211',
    }
}
```

##5. 設定完了

以上で、HerokuでMemcachedを使う準備ができました。
あとはHerokuへDjangoアプリをデプロイしてください。

#キャッシュする対象の指定方法について

キャッシュする対象(ビューやテンプレートなど)の指定に関しては、様々な方法があります。

naritoさんの[ブログ](https://narito.ninja/detail/75/)や、Django Advent Calendar 2018の14日目の記事である[shinyorkeさんのブログ](https://shinyorke.hatenablog.com/entry/django-cache)に詳しく記載されているので、そちらを参考にしていただければと思います。

私の過去のQiitaの記事でもurls.pyでcache_page関数を使う一例を記載しています。

- [Qiita - Djangoのキャッシュ機能を使って画面表示をもっと高速化する Memcached編](https://qiita.com/shonansurvivors/items/f2681aebfd8b08cee994)

#最後に少し自己紹介

ここまでお読みいただき、ありがとうございました。

私、やんばる([@shonansurvivors](https://twitter.com/shonansurvivors))は今年2018年の5月ごろからPythonを学び始め、その勉強の過程やDjangoで作った[Webサービス](https://www.sekaiisan.site)について[ブログに投稿](https://shonansurvivors.hatenablog.com/entry/2018/11/18/020512)したところ、非常に多くの方に読んでいただくことができました。

その後、ここ最近はそのサービスのレスポンス向上に取り組んできたため、そこで学んだDjangoのキャッシュ機能について、今回のAdvent Calendarのテーマとさせていただきました。

今後もPython、Djangoを学ぶ中で得た知識をQiitaに投稿していきたいと思いますので、どうぞよろしくお願い致します!