TL;DR
タイトル通り、Djangoで指定したhostにリダイレクトさせるmiddlewareを書こうとした。
見つかった記事が5年以上前のものと古く、Django v1.10以降のmiddlewareの書き方に対応していなかったので対応する書き方で書き直した。
middlewareで呼ばれる関数についてはこちらがわかりやすかった。
0.問題設定
例えばDjangoアプリケーションをherokuでデプロイし(example.herokuapp.com
)、お名前.comでドメイン(example.com
)を取得したとする。
この場合、example.com
からアクセスできるようになったとしても、
example.herokuapp.com
でも同様にアクセスできる。
これをリダイレクトするために、middlewareを作って対応した。
1.middleware作成
今回、プロジェクト直下に/lib/middleware.py
という名前でmiddlewareを作成。
クラス名はRedirectCorrectHostname
とする。
これを/{プロジェクト名}/settings.py
に追加する。
MIDDLEWARE = [
...
'lib.middleware.RedirectCorrectHostname',
...
]
ここがハマりポイント1で、v1.10より、MIDDLEWARE_CLASSES
からMIDDLEWARE
に変わった。(参考)
2.リダイレクト先のhostを指定
CORRECT_HOST = '127.0.0.1:8000'
これをsettings.CORRECT_HOST
として参照できる。
3.リダイレクトのmiddlewareを定義
from django.http import HttpResponsePermanentRedirect
from django.conf import settings
class RedirectCorrectHostname(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
return response
def process_view(self, request, view_func, view_args, view_kwargs):
# settingsにCORRECT_HOSTがあるか
if not getattr(settings, 'CORRECT_HOST', None):
return None
# settings.CORRECT_HOSTとアクセスしているhostが一致するか
if request.get_host() == settings.CORRECT_HOST:
return None
# 一致しなかった場合、settings.CORRECT_HOSTにリダイレクト
return HttpResponsePermanentRedirect(
'{scheme}://{host}{path}'.format(scheme=request.scheme,
host=settings.CORRECT_HOST,
path=request.get_full_path()))
詳しい説明はこちらを参照してほしいのだが、各メソッドについて軽く説明。
__init__
サーバ起動時に1度だけ呼び出される。初期化。必須。
__call__
リクエスト毎に呼び出されるメソッド。必須。
self.get_response()
実行前に処理を記述することで、view関数適用前に実行する共通処理を定義することができる。
process_view
view関数を呼び出す直前にhookされるメソッド。
- 実行されるview関数
- そのview関数への引数(例えばurlsで定義したパラメータ)
を知っている。
返り値として
- None
- HttpResponse
のどちらかを返す必要があり、ここにリダイレクト処理を定義した。
おわりに
リダイレクト処理なんて何人もやってそうなのに意外と記事がなかった......