LoginSignup
14

More than 3 years have passed since last update.

AzureのApp ServiceでDjangoを動かす際の躓きポイント

Last updated at Posted at 2019-05-05

以前の投稿「tabulatorを使って、データベースの更新にトライ(python版)」「Azure ML StudioとFlask連携によるWebアプリケーションサンプル」はFlaskを利用していましたが、この10連休を利用してDjangoにトライしてみました。

Djangoはフルスタックのフレームワークなだけあって、ファイルも多くそれぞれに正しく設定しないと動きませんでしたので、特に躓いた点を報告します。

demo

※07/02 15:00 機械学習のプログラムをDjango環境へ変更するのに伴いリンク先を変更しました。

インストール手順

1.Django Girls のチュートリアルをもとにローカルPCでDjangoアプリケーションを作成。

2.AzureのWebappsにFlaskサーバとは別にPythonサーバを作成。

3.Web Appsの内臓しているpython環境は固定領域に保存されていてライブラリの追加はできない為、webappsダッシュボードの「開発ツール」→「拡張機能」→「追加」でPython 3.6.4 x86を追加。

4.Djangoのライブラリ追加は、webappsダッシュボードの「コンソール」 からチェンジディレクトリーで移動→pipを(古いらしいので)バージョンアップ→Djangoをインストール。

cd \home\python364x86

d:\home\python364x86>python -m pip install --upgrade pip

d:\home\python364x86>pip install Django

5.ローカルで作成したファイルをFTPでアップ。

【躓きポイント1】各ファイルを正しく指定しなかった事によるエラーの対策が、なかなかわからなかった。

ローカルに作成したDjangoのフォルダ構造は、Django Girlsを参考にした場合は下記の様になっていると思います。これをアップする場合、「wwwroot」の下に「djangogirls」フォルダを作成しても、「djangogirls」フォルダは無しでフォルダとファイルを「wwwroot」の下に置いてもそれぞれの設定を正しく行えばよいのですが、それぞれの関連の理解が不十分で躓きました。

特に、settings.pyのINSTALLED_APPS = [(アプリを指定)] を間違えると、「RuntimeError: populate() isn't reentrant」というエラーになり、指定が間違っているという事になかなか気づきませんでした。

【理解したDjangoファイルの関連】

(1)WebサーバからはWsgiインターフェースを通じてweb.configで指定しているスクリプトエンジンと
      設定ファイルsettings.pyをもとに起動する。ローカル起動の場合(python manage.py runserver)は
      manage.pyの中で指定しているsettings.pyをもとに起動する。

(2)settings.pyの中でurl.pyを指定。ほかにINSTALLED_APPSでアプリ、
     TEMPLATES、STATICの設定でそれぞれファイルを指定する。


djangogirlsフォルダ
├── blogフォルダ
│   ├──templatesフォルダ
│   │   test.html(5)
│   ├── url.py(3’)どのviewを呼ぶか設定。
│   └── views_test.py(4)プログラムに相当、処理を行い結果をどのテンプレートに渡すか記述。
├── db.sqlite3
├── manage.py
└── mysiteフォルダ
    ├── settings.py
    ├── urls.py(3)要求されたurlの遷移を司る。アプリのurl(3’)へリダイレクトしたり、ここでどのviewを呼ぶか設定しても良い。
    └── wsgi.py

ソース

web.config
<!-- コメントは説明の為です。実ファイルにあるとエラーになります。 -->
<configuration>
  <appSettings>
    <add key="pythonpath" value="D:\home\site\wwwroot" />  <!-- ここが起点で以降ここからの
    相対ディレクトリとなります。wwwrootの下にdjangogirlsを設けたような場合、
    D:\home\site\wwwroot.djangogirlsとすれば以降の設定でdjangogirlsを略す事ができます。 -->

<configuration>
    <add key="WSGI_HANDLER" value="django.core.wsgi.get_wsgi_application()"  />
    <add key="DJANGO_SETTINGS_MODULE" value="mysite.settings" />  <!-- どのsettings.pyを読むか定義。 -->
    <add key="WSGI_LOG" value="D:\home\site\wwwroot\LogFiles\wfastcgi.log"/>    <!-- wfastcgiのログを出力。LogFilesフォルダは予め作成。-->
  </appSettings>

  <system.webServer>
    <handlers>
      <remove name="Python34_via_FastCGI" />  <!--静的ファイルがAzureデフォルトのPython34で処理しようとしてエラーになるのを回避します。  -->
      <add name="Python FastCGI"
           path="handler.fcgi"
           verb="*"
           modules="FastCgiModule"
           scriptProcessor="D:\home\python364x86\python.exe|D:\home\python364x86\wfastcgi.py"
           resourceType="Unspecified"
           requireAccess="Script" /> 
    </handlers>

    <rewrite>
      <rules>
        <rule name="Static Files" stopProcessing="true">
          <conditions>
            <add input="true" pattern="false" />
          </conditions>
        </rule>
        <rule name="Configure Python" stopProcessing="true">
          <match url="(.*)" ignoreCase="false" />
          <conditions>
            <add input="{REQUEST_URI}" pattern="^/static/.*" ignoreCase="true" negate="true" />
          </conditions>
          <action type="Rewrite" url="handler.fcgi/{R:1}" appendQueryString="true" />
        </rule>
      </rules>
    </rewrite>
    <httpErrors errorMode="Detailed"></httpErrors>
 <!-- エラーをhtmlに出力。内容はLogFilesと同じ。-->
  </system.webServer>
</configuration>

settings.py

import os

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

SECRET_KEY = 'am$+th5ttev9oa$77w9428jl*2bd-&fpvcy(dkigg99beg(kjh'

DEBUG = True

# 許可するサーバは自分のサーバ名に修正
ALLOWED_HOSTS = ['dja-vin.azurewebsites.net']

# 作成したアプリを追加
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blog',
]

MIDDLEWARE = [
    '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',
]

# ルートとして使用するコントローラ。デフォルトで生成されたものをそのまま利用。
ROOT_URLCONF = 'mysite.urls'

# CSSなどの静的ファイルの置き場所の設定
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATIC_URL = '/static/'

# テンプレートの置き場所の設定
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'mysite.wsgi.application'

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

LANGUAGE_CODE = 'ja'
TIME_ZONE = 'Asia/Tokyo'
USE_I18N = True
USE_L10N = True
USE_TZ = True
urls.py
from django.contrib import admin
from django.urls import path

from mysite import views
from blog   import views_test


urlpatterns = [
    path('', views.index, name='index'),
    path('test/', views_test.index, name='index'),
    path('admin/', admin.site.urls),
]

views_test.py
from django.shortcuts import render
from django.utils import timezone
from .models import Post
from django.http import HttpResponse

def index(request):
    posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
    param_value = request.GET.get("text1")
    params = {
        'msg'   : param_value,
        'posts' : posts
    }
    return render(request, 'blog/test.html', params)
test.html
{% extends "../base.html" %}
{% block body %}

{% load staticfiles %} <!-- Instruct Django to load static files -->
<link rel="stylesheet" type="text/css" href="{% static 'site.css' %}" />

<div>
    <h2>blogデータ表示</h2>
</div>


<span class="message">入力された値:{{ msg }}</span>

{% for post in posts %}
    <div>
        <p>----------------------------------------------</p>
        <h2>表題:  {{ post.title }}</h2>
        <p>発行日: {{ post.published_date }}</p>
        <p>内容:{{ post.text|linebreaksbr }}</p>
    </div>
{% endfor %}

{% endblock %}

【躓きポイント2】cssなどの静的ファイルを読み込ませる為にweb.configの設定が必要

settings.pyでstatic関連の設定をしても、cssが読み込めなかったのですが、ここで回避方法がわかりました。
web.configに「handlers remove name="Python34_via_FastCGI"」を設定します。そうしないと、Azureデフォルトのpython34\Scriptsが処理して、「Error occurred while reading WSGI handler」のエラーになっているのが、ブラウザF12でデバッグするとわかります。
また、adminプログラム用のcssは\site-packages\django\contrib\admin\static以下のフォルダをwwwroot以下に作成したstatic以下にコピーします。

【Azureでのデバッグについて】

ローカルサーバで動かす場合は、printでdos窓に表示されますが、Azureだとどこに吐き出されるのかわかりませんでした。そこで以下のようなファイル吐き出しでデバッグしていました。

log出力
STATIC_ROOT = os.path.join(BASE_DIR, 'static')

msg = "STATIC_ROOT = " + STATIC_ROOT #例えば上記行の内容を確認したい。
errlog = open('LogFiles/err.log','a')
errlog.write( msg + '\n')
errlog.close()

DjangoはFlaskに比べて、ユーザ管理やテーブルのメンテ画面等が自動的に生成されるのは便利ですが、ちょっと動きが重いかなという感じです。堅牢性や多重化などは両方ともWebサーバのwsgiインターフェースに依存しており、差異は無いと思われますので、構築するアプリの規模で使い分ければよいのかなと感じました。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14