在使用Azure的App Service运行Django时可能遇到的问题

使用之前的帖子“尝试使用tabulator进行数据库更新(Python版)”和“通过Azure ML Studio和Flask协作的Web应用程序示例”,其中使用了Flask,但在这个10天的假期里我尝试了使用Django。

鉴于Django是一个全栈框架,有许多文件需要正确配置才能正常运行,因此我将报告我在其中遇到的主要问题。

但是

※07/02 15:00 由于将机器学习程序更改为Django环境,我们已更改了链接目标。

安装步骤

参照Django Girls教程,在本地电脑上创建一个Django应用程序。

在Azure的Webapps中,除了创建一个Flask服务器,还创建了一个单独的Python服务器。

在Web应用程序中,Python环境被保存在固定的区域中,无法添加库。因此,您可以通过Web应用程序控制面板中的”开发工具”->”扩展功能”->”添加”来添加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

用FTP将在本地创建的文件上传。

【躓きポイント1】由于没有正确指定每个文件而导致错误的解决方法让我困惑不已。

如果按照Django Girls的参考,本地创建的Django文件夹结构应该如下所示。如果要上传,则可以在“wwwroot”下创建“djangogirls”文件夹,也可以在“wwwroot”下直接放置文件夹和文件,只要进行相应的正确配置即可。然而,我对相关的理解还不够深入,因此遇到了一些困难。

特别是,如果错误地指定了settings.py中的INSTALLED_APPS = [(指定应用程序)],将会出现“RuntimeError: populate() isn’t reentrant”错误,并且很难注意到指定有误的情况。


(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

醬料

<!-- コメントは説明の為です。実ファイルにあるとエラーになります。 -->
<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>


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
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),
]

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)
{% 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 %}

为了加载诸如CSS等静态文件,需要在web.config文件中进行设置

尽管在 settings.py 中进行了有关静态文件的设置,但无法加载 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`在命令行窗口显示,但在Azure上,我不知道它会被输出到哪里。因此,我使用以下的文件输出进行调试。

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接口,对于可靠性和多重性都没有差异,所以我觉得可以根据应用的规模来选择使用哪个。