akatak blog

プログラム初心者の50代ビジネスマンがセカンドキャリアを目指して働きながらPythonを中心に独学していましたが、昨年IT系企業に転職。新規事業開発の仕事をすることになりました。自らの覚え書きや成果物、感じたことなどを脈絡もなく書き連ねるブログです。

可視化フレームワークDashをDjangoで利用する

前回、Dashを利用して世界統計地図を描いてみましたが、これだとシングルページなんですよね。

Dash自体はマルチページにも対応してしてます。が、今後、Webアプリケーションとして機能を拡張していくことを考えたら、DjangoでDashを利用できると良いですよね。

いろいろ調べたところ、django-plotly-dashというパッケージが良さそうということで、試してみました。一部、苦労しましたが、うまくいきましたので、紹介します。

django-plotly-dash — django-plotly-dash documentation

前回Dashにて描いた世界地図をDjangoに統合する例を説明していきます。

環境

  • python==3.7.7
  • Django== 3.0.8
  • dash==1.11.0
  • dash-bootstrap-components==0.10.3
  • django-bootstrap4==2.2.0
    以下は、世界銀行データからグラフを作成するのに使います。
  • pandas==1.0.5
  • world-bank-data==0.1.3

まずはDjangoのプロジェクト・アプリを設定しておく

django-admin startproject djangomap

任意のプロジェクト名(ここではdjangomap)にてDjangoプロジェクトを設定します。 このプロジェクト名のフォルダができるので、そのフォルダ下に移動し、アプリケーションを作成します。 ここではworldmapというアプリケーション名にしています。

python manage.py startapp worldmap

Django-plotly-dashをインストールする

pip install django_plotly_dash

ドキュメンテーションに従って、以下もインストールしておきます。

pip install channels daphne redis django-redis channels-redis

さらに以下もインストールします。

pip install dpd-components dpd-static-support

settings.pyの設定

settings.pyを変更していきます。まずは、インストールしたアプリケーションを利用できるように設定します。

 # djangomap/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django_plotly_dash.apps.DjangoPlotlyDashConfig',  # django-plotly-dashにより追加
    'channels', # django_plotly_dashとともにchannelsをインストールしたため追加
    'channels_redis', # django_plotly_dashとともにchannels_redisをインストールしたため追加
    'bootstrap4',   #django-bootstrap4を利用する場合
    'worldmap.apps.WorldmapConfig' # 通常のdjangoアプリ設定に伴う追加
]

続いて、以下を丸々、settings.pyの最後に追加します。

  ### django_plotly_dashにて追加(ここから) ###

ASGI_APPLICATION = 'djangomap.routing.application'  # djangomapのところにはプロジェクト名が入ります。

CHANNEL_LAYERS = {
    'default':{
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            'hosts':[('127.0.0.1', 6379),],
        }
    }
}

STATICFILES_FINDERS = [
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
    'django_plotly_dash.finders.DashAssetFinder',
    'django_plotly_dash.finders.DashComponentFinder'
]

PLOTLY_COMPONENTS = [
    'dash_core_components',
    'dash_html_components',
    'dash_renderer',
    'dpd_components',
    'dpd_static_support',
    'dash_bootstrap_components',
]

X_FRAME_OPTIONS = 'SAMEORIGIN'

 ### django_plotly_dashにて追加(ここまで) ###

urls.pyを修正(プロジェクトレベル)

プレジェクトレベル(ここではdjangomapフォルダ直下)の`urls.py'に以下を追加する。

urlpatterns = [
    path('', include('worldmap.urls')), 
    path('admin/', admin.site.urls),
    path('django_plotly_dash/', include('django_plotly_dash.urls')), # これを追加
]

routing.pyを追加

プロジェクトフォルダ直下にrouting.pyを追加します。 routing.pyには以下を記述します。

from channels.routing import ProtocolTypeRouter

application = ProtocolTypeRouter({

})

Dashアプリの変更

前回作ったDashアプリを修正していきます。アプリケーションレベル(ここではworldmapフォルダ直下)に、dashアプリ - import dashfrom django_plotly_dash import DjangoDashに変更する
- dash.Dash(...)DjangoDash('WorldMap', add_bootstrap_links=True)に変更する
- if name == "main": app.run_server() を削除する

Dashアプリを表示するhtmlファイルを作成

アプリケーションレベル(ここではwouldmap直下)にtemplatesフォルダを作成、さらにworldmapフォルダを作成(Djangoの慣習)。そこに例えば、index.htmlを作成する(名前は任意)。そのファイルには以下の通り、記述する。

{% extends 'base.html' %}

{% block content %}

  {% load plotly_dash %}
  <div class="{% plotly_class name='WorldMap' %} card" style="height: 100%; width: 100%;">
    {% plotly_app name='WorldMap' ratio=1.0 %}
  </div>

{% endblock %}

順番が前後してしまいましたが、プロジェクトと同レベルにtemplatesフォルダを作成し、その中にbase.htmlを作成します。

そのbase.htmlには、ここではサンプルとして、Bootstrap4.3の以下のページの最初に出てくるNavbarをコピペして利用します。

getbootstrap.jp

views.pyとurls.py(アプリケーションレベル)

アプリケーションレベル(ここではworldmap)のviews.pyは通常通り。

 # views.py

from django.shortcuts import render

def index(request):
    return render(request, 'worldmap/index.html')

urls.pyでは、Dashアプリをインポートしておく必要があります。

  # urls.py
from django.urls import path
from . import views
from . import worldmap # これが必要

app_name = 'worldmap'

urlpatterns = [
    path('', views.index, name='index')
]

これで設定できました。さて、migrateを忘れるとうまく動きません。

python manage.py migrate

を忘れずに。そして、以下で起動してみると。

python manage.py runserver

f:id:akatak:20200725160431p:plain

うまく行きました!

スクリプトはこちらにアップしておきました。

GitHub - tak-akashi/djangomap

番外編

なお、上記の簡単な例をベースに、より機能強化を図ったサイトを作成し、Herokuにデプロイしましたので、こちらにもよろしければどうぞ。

https://egraph.herokuapp.com