Python/Flask

出典: フリー教科書『ウィキブックス(Wikibooks)』

Flask[編集]

FlaskはPythonで書かれたマイクロウェブフレームワークです。 特定のツールやライブラリを必要としないため、マイクロフレームワークに分類されます。 データベースの抽象化レイヤーやフォームの検証など、既存のサードパーティライブラリが共通機能を提供するコンポーネントは存在しません。 しかし、Flaskは拡張機能をサポートしており、Flask自体に実装されているかのようにアプリケーションの機能を追加することができます。 オブジェクトリレーショナルマッパー、フォームバリデーション、アップロード処理、様々なオープン認証技術、いくつかの一般的なフレームワーク関連ツールのための拡張機能が存在します。

インストール[編集]

Flaskのインストールにはいくつかの方法があります。

OS/パッケージマネージャが直接 Flask をサポートしている場合
FreeBSDがこれに当たります。
pip をサポートしている場合。
オペレーションシステムのパッケージマネージャから、Pythonのパッケージマネジャーである pip をインストールし、 pip を使って Flask をインストールします。

Flaskのパッケージがあるオペレーションシステムでは、pip ではなく、パッケージマネージャーからFlaskと依存パッケージをインストールしましょう。 混在すると、OSのパッケージマネージャーと pip の間で管理情報に矛盾が生じアップデートなどに支障をきたすようになっていまいます。

UNIX[編集]

多くの BSD UNIX は ports/pkgsrc/pkg で Flask をサポートしています。

FreeBSD[編集]

portsレクションに www/py-flask があります。

ソースコードからインストール

# make -C /usr/ports/www/py-flask install clean

バイナリーパッケージからインストール

# pkg install www/py-flask

Werkzeug や Jinja などの Flask が依存するパッケージも自動的にビルド/インストールされます。

また、静的なサイトを生成する www/py-frozen-flask もパッケージ化されています。

GNU/Linux[編集]

GNU/Linuxでは、ディストリビューションによってパッケージマネージャーや、パッケージアーカイブスが異なるので、お使いのパッケージマネージャーの利用方向に従ってインストールしてください。

Fedora Linux[編集]
sudo dnf update
sudo dnf search flask

を実行し、flask を名前に含むパッケージの一覧を表示し、その中から python3-flask を選びインストールします。

sudo dnf install python3-flask
GNU/Linuxの場合、インストールに管理者権限が必要なので、一般ユーザーのアカウントからは sudo を使って root 権限を行使します。

Fedora には、python3-flaskパッケージがあるので、 pip から flask をインストールすると、パッケージマネージャーで管理している依存パッケージ(Werkzeug や Jinja)と、 pip で管理している依存パッケージのバージョンが違ったりパスが違ったりする「キマイラ環境」ができてしまい、アップデートやアップグレードに支障を来たします。

インストール後の確認[編集]

ウェブアプリケーションを起動する前に、インストールが成功したか、またどのバージョンがインストールされたかを確認します。

flask-chk.py
import flask
import werkzeug
import jinja2

print(f"{flask.__version__=}")
print(f"{werkzeug.__version__=}")
print(f"{jinja2.__version__=}")
print("")

help(flask)
実行結果
flask.__version__='2.2.2'
werkzeug.__version__='2.2.2'
jinja2.__version__='3.1.2'

Help on package flask:

NAME
    flask

PACKAGE CONTENTS
    __main__
    app
    blueprints
    cli
    config
    ctx
    debughelpers
    globals
    helpers
    json (package)
    logging
    scaffold
    sessions
    signals
    templating
    testing
    typing
    views
    wrappers

FUNCTIONS
    __getattr__(name)
    
    escape(...)
        Replace the characters ``&``, ``<``, ``>``, ``'``, and ``"`` in the string with HTML-safe sequences. Use this if you need to display text that might contain such characters in HTML.
        
        If the object has an ``__html__`` method, it is called and the return value is assumed to already be safe for HTML.
        
        :param s: An object to be converted to a string and escaped.
        :return: A :class:`Markup` string with the escaped text.

DATA
    appcontext_popped = <blinker.base.NamedSignal object at 0x14ad5571e790...
    appcontext_pushed = <blinker.base.NamedSignal object at 0x14ad5571e730...
    appcontext_tearing_down = <blinker.base.NamedSignal object at 0x14ad55...
    before_render_template = <blinker.base.NamedSignal object at 0x14ad557...
    current_app = <LocalProxy unbound>
    g = <LocalProxy unbound>
    got_request_exception = <blinker.base.NamedSignal object at 0x14ad5571...
    message_flashed = <blinker.base.NamedSignal object at 0x14ad5571e880; ...
    request = <LocalProxy unbound>
    request_finished = <blinker.base.NamedSignal object at 0x14ad55714a30;...
    request_started = <blinker.base.NamedSignal object at 0x14ad55714880; ...
    request_tearing_down = <blinker.base.NamedSignal object at 0x14ad55714...
    session = <LocalProxy unbound>
    signals_available = True
    template_rendered = <blinker.base.NamedSignal object at 0x14ad557147f0...

VERSION
    2.2.2

FILE
    /usr/local/lib/python3.8/dist-packages/flask/__init__.py
バージョンが、flask=2.2.2/werkzeug=2.2.2/jinja2=3.1.2であること
インストール先が /usr/local/lib/python3.8/dist-packages/flask/__init__.py であることがわかります。
個々のメソッドのヘルプも help(flask.app) のように参照できます。

サービスの起動方法[編集]

はじめてのウェブアプリケーション[編集]

"Hello World" だけを返すウェブサービスをつくってみます。

hello.py
from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello():
    return "Hello World"

app.run()

起動してみましょう。

% python3.11 hello.py
 * Serving Flask app 'hello.py'
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit

http://127.0.0.1:5000 を開いてみます(127.0.0.0/8は、他のホストからはアクセスできないループバックインターフェースに割り当てられたアドレスです)。

Hello World
と表示されます。

Flaskを実行中の端末には

127.0.0.1 - - [22/Dec/2022 10:43:18] "GET / HTTP/1.0" 200 -
とcommon log format で表示されます。

http://127.0.0.1:5000/no-exist を開いてみましょう。

404 NOT FOUND
と表示されました(ブラウザによって表示が異なります)

Flaskを実行中の端末には

127.0.0.1 - - [22/Dec/2022 10:43:30] "GET /no-exist HTTP/1.0" 404 -
と表示されます。

Flaskを実行中の端末でFlaskを強制終了します。

^C%
^Cと表示されますが、CTRL-C(CTRLキーを押しながら C を押す)です。
解説
from flask import Flask
flaskパッケージからFlaskクラスをインポートとしています。
app = Flask(__name__)
変数 app をFlaskインスタンスで初期化し、以後appがウェブサービスの主体になります。__name__ には、実行しているプログラムのモジュール名が入ります。
@app.route('/')
@で始まる関数はPythonのデコレーターで、この場合は URL(のPATH)と関数を紐づけしています。
def hello():
関数 hello() の定義の開始
    return "Hello World"
機能は、文字列 "Hello World" を返すだけ。これが、HTTPレスポンスのボディーになります。
app.run()
サービスを起動します。具体的には、Flaskの内蔵ウェブサーバを localhost:5000 にバインドして実行します。

テンプレートの利用した動的なページ生成[編集]

Flaskは、Jinjaテンプレートエンジンと連携し、テンプレートベースの動的なウェブページの生成が可能です

ディレクトリーレイアウト[編集]

Flaskの既定のディレクトリーレイアウトでは、スクリプトのあるディレクトリーの下に、templates/ という名前のディレクトリーを掘り、そこにテンプレートを用意します。

2つのテンプレートファイルと1つのスクリプトを用意します。

templates/top.html
<!DOCTYPE html>
<html>
  <head>
    <title>Index</title>
  </head>
  <body>
    <ol>
{% for who in ["world", "flask", "python"]%}
      <li><a href="{{who}}">{{who}}</a>
{% endfor %}
    </ol>
  </body>
</html>
templates/echo.html
<!DOCTYPE html>
<html>
  <head>
    <title>Hello, {{who}}</title>
  </head>
  <body>
    <p>Hello, {{who}}</p>
    <a href=".">Top</a>
  </body>
</html>
echo.py
from flask import Flask, render_template

app = Flask(__name__)

@app.route("/", methods=["GET", "POST"])
def index():
    return render_template("top.html")

@app.route("/<name>", methods=["GET", "POST"])
def echo(name):
    return render_template("echo.html", who=name)

if __name__ == "__main__":
    app.run(debug=True, host='127.0.0.1', port=5555, threaded=True)
hello.py の Flask に加え render_template も import しています。
@app.route() に新たに与えているキーワード引数 methods は、HTTPのメソッドを指定しています。ディフォルトは GET だけをルーティングします。
"/<name>" は引数付きのURLで、この場合は変数 name に / 以降の引数が入ります。
if __name__ == "__main__": は、メインスクリプトとして呼ばれた場合だけ、つづくブロックを実行します。
app.run() の新たな引数
debug=True
ウェブデバッガーを有効にする
host
バインドするアドレス
port
バインドするポート
threaded=True
マルチスレッドを有効にする

Jinja[編集]

Jinja は、Python で実装されたテンプレートエンジンで、Flaskウェブアプリケーションフレームワークの一部として提供されていますが、単体で使用することも可能です。

簡単な Jinja の使用例[編集]

Example.html.jinja
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>{{ title }}</title>
  </head>
  <body>
    <ul>
{# Jinja の for 繰返し構文の例 #}
{% for item in items %}
      <li>{{ 2 * item + 1 }}</li>
{% endfor %}
{# Jinja の for 繰返し構文の例 #}
# for item in items
      <li>{{ 2 * item + 1 }}</li>
# endfor
    </ul>
  </body>
</html>
Main.py
from jinja2 import Template, Environment, FileSystemLoader

env = Environment(
    loader=FileSystemLoader('./', encoding='utf8'),
    line_statement_prefix = '#',
    line_comment_prefix = '##'
)
tmpl = env.get_template('Example.html.jinja')
print(tmpl.render(
    title = 'Simpla Template Example',
    items = range(0, 6)
))
実行結果(HTML)
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>Simpla Template Example</title>
  </head>
  <body>
    <ul>


      <li>1</li>

      <li>3</li>

      <li>5</li>

      <li>7</li>

      <li>9</li>

      <li>11</li>


      <li>1</li>
      <li>3</li>
      <li>5</li>
      <li>7</li>
      <li>9</li>
      <li>11</li>
    </ul>
  </body> 
</html>
レンダリング例
  • 1
  • 3
  • 5
  • 7
  • 9
  • 11
  • 1
  • 3
  • 5
  • 7
  • 9
  • 11
{{ }} でテンプレート中で変数(キーワード引数)や関数を参照できます。
{% for ループ変数 in コレクション %} から {% endfor %} の間で反復され、このブロックでループ変数を参照できます。
通常の Python のコードと異なり、{% for %} ループを抜けると、ループ変数は参照できません。このようにJinjaテンプレートはPythonと似た構文が使えますが、独立したサンドボックスで実行されており、Pythonとは別の言語であることに注意が必要です。
{#から#}までが、Jinjaテンプレートのコメントで、出力(この場合はHTML)には含まれません。

式の埋め込み[編集]

{{ }} でテンプレート中で変数(キーワード引数)や関数を参照できます。

変数への代入[編集]

{% set 変数 = %} でテンプレート中で変数に値を代入できます。

コメント[編集]

{# コメント #}がJinjaテンプレートのコメントの構文で、出力には含まれません。

制御構造[編集]

Jinjaには、条件分岐と反復の制御構造があります。

条件分岐[編集]

if[編集]

{% if x > 0 %}
x > 0
{% elif x < 0 %}
x < 0
{% elif x == 0 %}
x == 0
{% else %}
{{ x }}
{% endif %}
構文
{% if 式1 %}
ブロック1
{% elif 式2 %}
ブロック2
      ︙
{% elif 式n %}
ブロックn
{% else %}
ブロック
{% endif %}
elif 式 + ブロック と else + ブロック は省略可能です。

反復[編集]

for[編集]

構文
{% for ループ変数 in コレクション %}
ブロック
{% endfor %}
for のブロックの中では、特殊変数 loop を参照することでイテレーション回数を参照できます。
loop.index
現在、何周目かを1から順に返す
loop.index0
現在、何周目かを0から順に返す
loop.first
最初の周回なら True、そうでなければ False を返す。
loop.last
最後の周回なら True, そうでなければ False を返す。
length
ループのイテレーション回数
コレクションは、リスト、辞書、タプルなどで概ねPythonのforと同じ挙動ですが、ループ変数のスコープがループに閉じているところが違います。

改行の制御[編集]

 {% for item in range(1, 5) %}
       <li>{{ item }}</li>
 {% endfor %}

      <li>1</li>
 
      <li>2</li>
 
      <li>3</li>

      <li>4</li>
と冗長な空行を生成しますが、
 {% for item in range(1, 5) -%}
       <li>{{ item }}</li>
 {% endfor %}

と %} を -%} とすることで

<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
のように改行を抑止できます。

マクロ[編集]

マクロ( macro )機能を使うと、繰返し使うフレーズをテンプレートの中で定義し、呼出しという形で再利用できます。

書式
{% macro マクロ名(仮引数リスト)  %}
    処理内容
{% endmacro %}
マクロの呼出し
{{ マクロ名(実引数リスト) }}
{% macro func(arg)  %}
 <span style="color:blue">  {{ arg }} </span>
{% endmacro %}

{{ func("おはよう") }}
実行結果
 <span style="color:blue">  おはよう </span>
レンダリング例
おはよう

変数と型[編集]

Jinjaでは、Pythonのすべての組込み型を render_template() の引数として受取ることができ、反復構文を使うことで自由度の高いテンプレートを作ることができます。

Example.html.jinja
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>jinja -- example</title>
  </head>
  <body>
## line statment を使っています
# macro show(a)
<ul>
# for x in a
#   set type = x.__class__.__name__
  <li>{{ x }}({{ type -}})
#   if x is mapping
  <dl>
#     for key, value in x.items()
  <dt>{{key}}({{key.__class__.__name__}})<dd>{{value}}({{value.__class__.__name__}})
#     endfor
  </dl>
#   elif x is iterable and x is not string
  {{ show(x) -}}
#   endif
# endfor
</ul>
# endmacro
{{ show(args) -}}
  </body>
</html>
Main.py
from jinja2 import Template, Environment, FileSystemLoader

env = Environment(
    loader=FileSystemLoader('./', encoding='utf8'),
    line_statement_prefix = '#',
    line_comment_prefix = '##'
)
tmpl = env.get_template('Example.html.jinja')
print(tmpl.render(args = (
    123,
    22/7,
    "abc",
    0 == 0,
    ['Hello', 'World', 9],
    ('Hello', 'World', 9),
    {'cat':'tama', 'dog':'pochi', 'year':1776},
    {'cat', 'dog', 'bird'},
    range(1,10)
)))
実行結果(HTML)
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>jinja -- example</title>
  </head>
  <body>

<ul>
  <li>123(int)
  <li>3.142857142857143(float)
  <li>abc(str)
  <li>True(bool)
  <li>['Hello', 'World', 9](list)
  <ul>
  <li>Hello(str)
  <li>World(str)
  <li>9(int)
</ul>
  <li>('Hello', 'World', 9)(tuple)
  <ul>
  <li>Hello(str)
  <li>World(str)
  <li>9(int)
</ul>
  <li>{'cat': 'tama', 'dog': 'pochi', 'year': 1776}(dict)
  <dl>
  <dt>cat(str)<dd>tama(str)
  <dt>dog(str)<dd>pochi(str)
  <dt>year(str)<dd>1776(int)
  </dl>
  <li>{'bird', 'cat', 'dog'}(set)
  <ul>
  <li>bird(str)
  <li>cat(str)
  <li>dog(str)
</ul>
  <li>range(1, 10)(range)
  <ul>
  <li>1(int)
  <li>2(int)
  <li>3(int)
  <li>4(int)
  <li>5(int)
  <li>6(int)
  <li>7(int)
  <li>8(int)
  <li>9(int)
</ul>
</ul>
</body> 
</html>
レンダリング例
  • 123(int)
  • 3.142857142857143(float)
  • abc(str)
  • True(bool)
  • ['Hello', 'World', 9](list)
    • Hello(str)
    • World(str)
    • 9(int)
  • ('Hello', 'World', 9)(tuple)
    • Hello(str)
    • World(str)
    • 9(int)
  • {'cat': 'tama', 'dog': 'pochi', 'year': 1776}(dict)
    cat(str)
    tama(str)
    dog(str)
    pochi(str)
    year(str)
    1776(int)
  • {'bird', 'cat', 'dog'}(set)
    • bird(str)
    • cat(str)
    • dog(str)
  • range(1, 10)(range)
    • 1(int)
    • 2(int)
    • 3(int)
    • 4(int)
    • 5(int)
    • 6(int)
    • 7(int)
    • 8(int)
    • 9(int)
キーワード引数(テンプレートの変数)args は Tuple で、Python の代表的な組込み型の値を要素にしました。
ここで定義している macro show(a) は、引数の値と型を表示し、引数がコレクションだったら再帰的に要素を表示します(マクロは再帰できます)。
この例では、line statment (行志向構文)を使っているので{% 文 %} の対応関係を目で追う必要なくなり可読性が高くなります。

テンプレートの継承[編集]

Jinjaでは、テンプレートを別のテンプレートから雛形として継承する事ができます。

Base.html.jinja
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>{% block title %}Jinja::Example{% endblock %}</title>
  </head>
  <body>
  {% macro hr() %}
  <hr>
  {%endmacro %}
  {% block content %}
  {% endblock %}
  </body>
</html>
Example.html.jinja
{% extends "Base.html.jinja" %}
{% block title %}ホーム - {{ super() }}{% endblock %}
{% block content %}
<h1>ホーム</h1>
{{ hr() }}
<p>Example.html.jinja の block content</p>
{% endblock %}
Main.py
from jinja2 import Template, Environment, FileSystemLoader

env = Environment(
    loader=FileSystemLoader('./', encoding='utf8'),
    line_statement_prefix = '#',
    line_comment_prefix = '##'
)
tmpl = env.get_template('Example.html.jinja')
print(tmpl.render())
実行結果(HTML)
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>ホーム - Jinja::Example</title>
  </head>
  <body>
  
<h1>ホーム</h1>

  <hr> 

<p>Example.html.jinja の block content</p>

  </body>
</html>
レンダリング例
ホーム

Example.html.jinja の block content

解説
継承元のテンプレート Base.html.jinja では、開始タグ {% block ブロック名 %}から終了タグ {% endblock %} で差替え対象を決めます。
継承先のテンプレート Example.html.jinja では、開始タグ {% block ブロック名 %}から終了タグ {% endblock %} で差替える内容を気まます。
継承先のブロックの中では、関数 super() で、継承元の差替え対象を参照できます。

ブロックは、マクロと異なり継承元では定義を行うだけで、展開は継承先だけで行なえます。また継承元も継承先も同じ開始タグと終了タグを使うので、多段継承(孫テンプレートを作ること)はできません。定義を blockdef、展開を blockref のように別の名前にすれば構文的には多段継承できますが、その場合「super()が何を表すのか」「循環継承が起こったらどうするか?」など意味論・運用論的な問題を多数生んでしまうので、多段継承を妨げたのは設計上のロバストな選択です。 また、継承元で定義したマクロを、継承先で展開することはできます。

include[編集]

block と extends によるテンプレート継承が雛形だとすれば、include による包含は部品化です。

[TODO:コード例]

filter[編集]

filter には、式指向のフィルターとブロック指向のフィルターとがあります。

[TODO:コード例]

Django[編集]

Flaskに次ぐシェア2位のPythonベースのウェブアプリケーションフレームワークにDjangoがあります。

単独のページとして立項できる内容と信頼性を得るまで、Flaskの下におきました。

インストール[編集]

Djangoのインストールにはいくつかの方法があります。

OS/パッケージマネージャが直接 Django をサポートしている場合
FreeBSDがこれに当たります。
pip をサポートしている場合。
オペレーションシステムのパッケージマネージャから、Pythonのパッケージマネジャーである pip をインストールし、 pip を使って Flask をインストールします。

Djangoのパッケージがあるオペレーションシステムでは、pip ではなく、パッケージマネージャーからDjangoと依存パッケージをインストールしましょう。 混在すると、OSのパッケージマネージャーと pip の間で管理情報に矛盾が生じアップデートなどに支障をきたすようになっていまいます。

UNIX[編集]

多くの BSD UNIX は ports/pkgsrc/pkg で Django をサポートしています。

FreeBSD[編集]

portsレクションに www/py-django があります。

ソースコードからインストール

# make -C /usr/ports/www/py-django install clean

バイナリーパッケージからインストール

# pkg install www/py-django

GNU/Linux[編集]

GNU/Linuxでは、ディストリビューションによってパッケージマネージャーや、パッケージアーカイブスが異なるので、お使いのパッケージマネージャーの利用方向に従ってインストールしてください。

Fedora Linux[編集]
sudo dnf update
sudo dnf search django

を実行し、django を名前に含むパッケージの一覧を表示し、その中から python3-django を選びインストールします。

sudo dnf install python3-django
GNU/Linuxの場合、インストールに管理者権限が必要なので、一般ユーザーのアカウントからは sudo を使って root 権限を行使します。

Djangoのバージョン確認の方法

python -m django --version

使い方[編集]

Django を使うには、コマンドラインを使う必要があります。


まず、プロジェクトのディレクトリ群を作らないといけないのですが、さすがにこれは自動生成してくれるコマンドがあります。

コマンド

django-admin startproject プロジェクト名

で、まずプロジェクトを作ります。

上記コマンドを使えば、Django用のプロジェクトのディレクトリを自動生成してくれます。

たとえば、 「projtest」というプロジェクトを作るなら

django-admin startproject projtest

になるわけです。

そして、このプロジェクト内でこれから作業するので、移動コマンドcdを使い、

cd プロジェクト

で、さきほど作成したプロジェクトのディレクトリ内に移動します。


コマンド

python manage.py runserver 

を使うと、Django の ウェブサーバーが立ち上がります。

ウェブブラウザで、

http://127.0.0.1:8000/

でアクセスできます。

Django の初期ページ

まだ何もユーザー側でHTMLを作っていないので、初期設定のHTMLページが表示されるので、表示ページには英文およびロゴマークでロケットの打ち上げ絵が書かれています。水色っぽいロケットの打ち上がってるイラストが出たら、とりあえず、ここまでの作業は成功です。


サーバ立ち上げのコマンドの冒頭は、 django-admin ではなく Python ですので、間違えないようにしましょう。なんでここだけPythonなのか謎ですが、そういう仕様なので、従うしかありません。

なお、自動作成ずみのプロジェクト用ディレクトリ内にすでに manage.py というスクリプトがあり、それを上記コマンド Python manage.py runserver で実行している仕組みです。


なお、サーバを終了するには、CTRLキー を押しながら C を押します。(Flaskと同じ終了コマンド)


次回以降のサーバの立ち上げは

cd プロジェクト名
python manage.py runserver

になります。

自作HTMLページの立ち上げ[編集]

では、これからホームページを作りましょう。Djangoではホームページは「アプリ」に分類されるので、コマンド

Python manage.py startapp アプリ名

で、まずDjangoアプリを作ります。

このコマンドを実行する場所は、どこでもいいのですが、プロジェクト内でしたほうがラクなので、中で作成した場合、コマンドライン画面は

[ユーザ名@localhost プロジェクト名]$  Python manage.py startapp アプリ名

のようになります。


今回、最終的に作りたいのはホームページなので、たとえば「hptest」というアプリ名を作ったとしましょう。


Django用ディレクトリ内に自動作成されたアプリ名ディレクトリの中に

views.py
from django.shortcuts import render

# Create your views here.

というファイル名と上記のコード内容のファイルがありますので、それをマウスで右クリックして、普通に開き、これから編集することで、ホームページ作成する仕組みです。


これを編集し、下記のような関数を付け足します。関数名(func)とその引数(arg)は自由に設定できますが、「render」はそのままにしてください。

views.py 変更後
from django.shortcuts import render

# Create your views here.
def func(arg):
    return render(arg, 'testpage.html')


書式はもちろん

def 関数名(引数名):
    return render(引数名, 'ウェブページの名前.html')

です。


次に、プロジェクト名と同名のディレクトリが、プロジェクトに入った階層にあるので、その同名ディレクトリに、マウスで移動します。 そして、その同名ディレクトリ内に、urls.py というファイルが存在し、↓のほうに、下記のようなコードが書かれています。

プロジェクト側 urls.py の抜粋
from django.contrib import admin
from django.urls import path

urlpatterns = [
    path('admin/', admin.site.urls),
]

このファイルのこのコード部分を下記のように書き換えます。

from django.contrib import admin
from django.urls import path, include   # 追加せよ include を

urlpatterns = [
    path('admin/', admin.site.urls),
    path('アプリ名/', include('アプリ名.urls') )   # 追加
    # たとえば path('hptest/', include('hptest.urls') )
]


次に、アプリ側に、urls.py という同名のファイルを作りますが(初期設定では用意されてないので、ファイルを新規作成してください)、中身は別です。下記のようなコードをアプリ側に書きます。

アプリ側 urls.py の抜粋
from django.urls import path
from . import views

urlpatterns = [
    path('templates/', views.func, name='func'),
]


そして、さらに、「templates」ディレクトリを作り、そこに最終的に表示したいHTMLを入れます。このディレクトリ名は、必ず「templates」でないといけません。(アプリ側 urls.py のコード中のpath('templates/', といっしょに別ディレクトリ名に書き換えて違うディレクトリ名にしても、エラーになります。なので、必ず「templates」というファイル名にしてください。)


    path('templates/', views.func, name='func'),

の第一引数の部分は、ウェブブラウザなどで「templates」のメッセージが送られた場合に、テンプレートディレクトリにあるファイルで対応する事を言っています。

なので、たとえば、第一引数を別名にして

    path('tbetumei/', views.func, name='func'),

のようにしても、ウェブブラウザでのアクセス時にURL欄に

http://localhost:8000/hptest/betumei/

と入力すると、ブラウザからtemplatesディレクトリ内のHTMLなどにアクセスできてしまいます。ですが、まぎらわしいので、第一引数は「templates」のままに、しておいてください。


このtemplatesディレクトリに入れるHTMLには、とりあえず、

<h2>Hello Django World!</h2>

と書いてあるとしましょう。


さらに、プロジェクト側にある setting.py に、INSTALLED_APPS という項目があり、最初は

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

と書かれていますが、これに私達の作成するアプリ名をつけたすことで、そのアプリが追加されたことを知らせます。

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'アプリ名', # たとえば 'hptest',
]

あとは、サーバを立ち上げて、ウェブブラウザで

http://localhost:8000/アプリ名/templates/

にアクセスすれば、HTMLファイルの内容が表示されます。(上述のコード例の場合なら、 http://localhost:8000/hptest/templates/ にアクセスする事になります。 )


表示結果

大きな文字で

Hello Django World!

と表示されれば成功です。

ログインページの作成など[編集]

Django では、ログインページそのものを自動作成する機能もあり Auth といいますが、設定が必要です。

これとは別に、ログインページでよく使いそうな、Eメールアドレス入力フォームや、会員サイトでの入会時の生年月日の登録などで使いそうな年月日入力フォームなど、各種の入力フォームを、テンプレートで自動作成する機能があり、Formクラスと言います。

Eメール入力フォームなら、メールアドレス形式以外の文字列が入力されても、送信を禁止します。このように、入力内容を自動的に検査することを「バリデーション」といいます。Formクラスを使うと、バリデーションの機能を使えます。

また、その他の一般のDjangoの入力フォームでも、入力時の必須項目などを設定できます。たとえば、登録ページでユーザー名が未入力なのに「送信」ボタンの押された場合には、「この項目を入力してください」のような警告メッセージを、ウェブページ上で出させて、送信させないでユーザーに再入力させる事ができます。

Djangoなどのフルスタックウェブアプリケーションフレームワークを使う利点として、サーバー製作者は上述のように、入力欄のチェック機能を自作する手間が省けます。

複数ページの作成[編集]

いきなりログインページを作っても、複雑で理解が浅くなってしまうので、まずは、リンクで結ばれている複数のHTMLページをアップロードする方法を学びましょう。


templates にHTMLファイルが2つあるとして、

testpage.html
testpage2.html

というファイルがあるとしましょう。


まず、これをアップロードするために、コードを下記のように書き換えます。

アプリ側 urls.py
from django.urls import path
from . import views

urlpatterns = [
    path("testpage.html", views.func, name="func"),
    path("testpage2.html", views.func2, name="func2"),
]

なお、(アプリ側でなく)プロジェクト側 urls.py の抜粋はそのままにしておきます。

さて、views.pyに、2ページ目のHTMLのための関数を追加する必要があります。

views.py
from django.shortcuts import render

# Create your views here.
def func(arg):
    return render(arg, "testpage.html")


def func2(arg):
    return render(arg, "testpage2.html")


そして、それぞれのHTMLファイルには

testpage.html
<a href="http://localhost:8000/hptest/testpage2.html">他ページにワープ</a> <br>
testpage.html
ここは2ページ目です。

と書いてあるとしましょう。

説明の簡単化のため、まです、各種の Django テンプレートは使わないでおきましょう。

これだけすれば、とりあえず、ウェブブラウザで、

http://localhost:8000/hptest/testpage.html

にアクセスすれば、1ページ目を表示できます。

そして、ブラウザに表示されたリンク文をクリックすれば、2ページ目に移動できます。

2ページ目に移動したとき、アドレス欄の末尾が、きちんと2ページ目のファイルである testpage2 に変わっている事を確認しましょう。つまり、

http://localhost:8000/hptest/testpage2.html

というふうに、なっているハズです。

とりあえず、これで読者のアナタは、Djangoに複数のHTMLページをアップロードする事ができました。

では、今度はHTMLファイルのリンクを、Djangoテンプレートタグの一種である URLテンプレートタグ を使って書き換える方法を学びましょう。

単に、1ページ目のhrefタグの引数を、下記のようにurlテンプレートタグを使って書き換えるだけです。なお、前回との表示の区別のため、下記コードでは表示される文章を少々、追加してあります。

testpage.html
<a href="{% url "func2" %}">他ページにワープ. なお文章を書き換えてあります。</a> <br>

参考のため、2ページ目のHTMLも再掲しておきます。

testpage.html
ここは2ページ目です。書き換え後のワープ。

あとはもう、

http://localhost:8000/hptest/testpage.html

にアクセスすれば、前回と同様のアクセス結果になります。