sanoto_nittc’s diary

主にAdvent Calendarの記事を書きます

Djangoでサブドメインを扱う(django-hosts)

はじめに

この記事は プロコンゼミ(SPC同好会) その1 Advent Calendar 2018 15日目の記事です
adventar.org

今年の高専プロコン、弊部課題部門はPythonDjangoと戯れていました
その際、機能ごとにサブドメインで分けようという話になったのですが・・・
目的のモノを見つけるのにかなり手こずってしまったので、ここに書いておこうと思います

探す

求めているものは
「一つのDjangoプロジェクトの中で、複数のサブドメインを扱うための何か」
です

django subdomains 等で探してみると、django-subdomains というものに行き当たると思います

ですが、これは罠です

実際に使ってみると分かりますが、少なくとも現時点のdjango-subdomainsはDjango 2.Xに対応しておらず、使おうとするとエラーが出ます

結論

django-hosts を使いましょう

実際に使ってみる

基本 ドキュメント を見れば使い方は書いてありますが、やっぱり例がないとどうしてもわかりにくいですよね

ここでは実際にプロコンで書いたコードを紹介しながら説明していきたいと思います

インストール

まあここは普通にpipで入れます

pip install django-hosts

前提

こういうプロジェクトだと仮定します 今回は、もともと一つのドメイン内で管理していたものを、機能(アプリ)ごとにドメインを使い分けるようにします

myapp1/urls.pyはmysite/urls.pyから読み込んでいるものとします (例えばmysite/urls.pyのurlpatternsに path('', include('myapp1.urls')) と書いておく、など)

プロジェクト内で使えるようにする

mysite/settings.pyを変更します

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'myapp1',
    'myapp2',
    'myapp3',
    'django_hosts',    # <- 追加
]
 MIDDLEWARE = [
    'django_hosts.middleware.HostsRequestMiddleware',    # <- 追加
    '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',
    'django_hosts.middleware.HostsResponseMiddleware',    # <- 追加
]

ROOT_URLCONF = 'mysite.urls'
ROOT_HOSTCONF = 'mysite.hosts'    # <- 追加
DEFAULT_HOST = ''    # <- 追加

DEFAULT_HOSTにはデフォルトにしたいサブドメインを設定します
www.example.comをデフォルトにしたいのなら DEFAULT_HOST = 'www' と書きます

サブドメインの設定を書く

mysite/hosts.pyというファイルを新たに追加し、urls.py的な要領で書いていきます

from django.conf import settings
from django_hosts import patterns, host

host_patterns = patterns(
    '',
    host(r'', settings.ROOT_URLCONF, name='app1'),
    host(r'app2', 'myapp2.urls', name='app2'),
    host(r'app3', 'myapp3.urls', name='app3'),
)

patterns()の最初の引数 ''プレフィックス(接頭辞)らしいので、たぶんドメインの頭に共通で何か入れたい時に使うのでしょう
果たしてそんな時があるのかどうか、疑問ではありますが・・・

仕上げ

もしmysite/urls.pyでmyapp2/urls.pyやmyapp3/urls.pyを読み込んでいる場合は、読み込まないようにしましょう
例えば path('', include('myapp2.urls')) などがあれば全て消します
なぜかというと、hosts.pyで

  • mysite/urls.py
  • myapp2/urls.py
  • myapp3/urls.py

これらを読み込んでいる(配置している)からです
せっかくサブドメインに配置したのに、example.comにも配置しておく意味はありません
消し忘れには注意しましょう

おわりに

django-hostsは実装がとても楽です
djangoサブドメインを扱うときは、ぜひこれを使ってみて下さい

Advent Calendar、16日目の記事は弊部部長が担当です
さぞ素晴らしい記事を書いてくれることでしょう