dackdive's blog

新米webエンジニアによる技術ブログ。JavaScript(React), Salesforce, Python など

[django]アプリケーション名を取得する

テンプレートなどにアプリケーション名を直書きしたくないので
取得する方法がないか調べてみた話。

はじめに(やりたいこと)

Google App Engineに限らずだと思うのですが、djangoのアプリケーションを複数作成していて
以下のようにurls.pyを定義し、urlによってアプリケーションを分けているとします。

urls.py

from django.conf.urls import patterns, include, url

urlpatterns = patterns('',
    url(r'^app_A/$', include('app_A.urls')),
    url(r'^app_B/$', include('app_B.urls')),
    url(r'^app_C/$', include('app_C.urls')),
    ...
)

この場合、たとえば特定のアプリケーションapp_Aのテンプレートにボタンを設置しようとなると
そのactionのURLは/app_A/actionというように

/[アプリケーション名]/[実行したいアクションのURL]

となりますよね。

公式チュートリアルのguestbookでいえば、テンプレートには

index.html(抜粋)

<form action="/sign?guestbook_name={{ guestbook_name }}" method="post">
    <div><textarea name="content" rows="3" cols="60"></textarea></div>
    <div><input type="submit" value="Sign Guestbook"></div>
</form>

と書いてますが、このアプリケーションをhttp://localhost:8080/guestbook以下に配置した場合、ボタンのURLは

<form action="/guestbook/sign?guestbook_name={{ guestbook_name }}" method="post">
    <div><textarea name="content" rows="3" cols="60"></textarea></div>
    <div><input type="submit" value="Sign Guestbook"></div>
</form>

としたいはずです。
が、このようにテンプレートに直接アプリケーション名を埋め込むのは何だか抵抗があります。
テンプレートなので、{{ app_name }}というような形でview側から値を渡してあげたいです。

というわけで、どうやったら実現できるか調べました。

ここにあった

Stackoverflowに同じような質問をしている人が。

django - How to get the name of current app within a template? - Stack Overflow

アプリケーション名を取得する2つの方法

上のサイトに書かれていた方法としては次の2つがありました。

  1. context processorを使う
  2. (django1.5以降) requestオブジェクトのresolver_match属性を使う

ここでは、2.の方法でやってみます。

方法

プロジェクトのurls.pyで次のようにapp_nameを指定します。

from django.conf.urls import patterns, include, url

urlpatterns = patterns('',
    # includeメソッドの引数にapp_nameを定義する
    url(r'^app_A/$', include('app_A.urls', app_name='app_A')),
    url(r'^app_B/$', include('app_B.urls', app_name='app_B')),
    url(r'^app_C/$', include('app_C.urls', app_name='app_C')),
    ...
)

includeapp_nameの他、namespaceも指定できるようです。
(が、そっちが何に使われるのかは不明です)

(参考)https://docs.djangoproject.com/en/1.7/ref/urls/#django.conf.urls.include

そして、views.py内でrequest.resolver_match.app_nameを取得し、テンプレート変数にセットします。

views.py

# /app_A/XXX というリクエストの時に呼ばれるメソッド
def main_page(request):
    (中略)
    template_values = Context({
        'app_name': request.resolver_match.app_name,
        ...
            })

    return HttpResponse(loader.get_template('index.html').render(template_values))

index.html(修正後、抜粋)

<form action="/{{ app_name }}/sign?guestbook_name={{ guestbook_name }}" method="post">
    <div><textarea name="content" rows="3" cols="60"></textarea></div>
    <div><input type="submit" value="Sign Guestbook"></div>
</form>

これで、アプリケーション名を直接テンプレートに書かなくても済むようになりました。

リファレンス

https://docs.djangoproject.com/en/1.5/ref/urlresolvers/#django.core.urlresolvers.ResolverMatch

https://docs.djangoproject.com/en/1.5/ref/request-response/