Python3でFlaskを使用してWebアプリケーションを作成する方法
序章
Flask は、PythonでのWebアプリケーションの作成を容易にする便利なツールと機能を提供する小型で軽量のPythonWebフレームワークです。 単一のPythonファイルのみを使用してWebアプリケーションをすばやく構築できるため、開発者に柔軟性を提供し、新しい開発者にとってよりアクセスしやすいフレームワークになります。 Flaskも拡張可能であり、特定のディレクトリ構造を強制したり、開始する前に複雑なボイラープレートコードを必要としたりすることはありません。
このチュートリアルの一部として、 Bootstrapツールキットを使用して、より視覚的に魅力的なアプリケーションのスタイルを設定します。 Bootstrapは、レスポンシブWebページをWebアプリケーションに組み込むのに役立ちます。これにより、これらの目標を達成するために独自のHTML、CSS、およびJavaScriptコードを記述しなくても、モバイルブラウザーでも適切に機能します。 このツールキットを使用すると、Flaskがどのように機能するかを学ぶことに集中できます。
Flaskは、 Jinjaテンプレートエンジンを使用して、変数、ループ、リストなどの使い慣れたPythonの概念を使用してHTMLページを動的に構築します。 これらのテンプレートをこのプロジェクトの一部として使用します。
このチュートリアルでは、Python3でFlaskとSQLiteを使用して小さなWebブログを作成します。 アプリケーションのユーザーは、データベース内のすべての投稿を表示し、投稿のタイトルをクリックしてその内容を表示し、データベースに新しい投稿を追加したり、既存の投稿を編集または削除したりできます。
前提条件
このガイドに従う前に、次のものが必要です。
- ローカルPython3プログラミング環境については、ローカルマシン用のPython3シリーズのローカルプログラミング環境をインストールおよびセットアップする方法のチュートリアルに従ってください。 このチュートリアルでは、プロジェクトディレクトリを呼び出します
flask_blog
. - データ型、条件文、 forループ、関数などのPython3の概念の理解。 Pythonに慣れていない場合は、 Python3シリーズのコーディング方法を確認してください。
ステップ1—Flaskのインストール
このステップでは、Python環境をアクティブ化し、pipパッケージインストーラーを使用してFlaskをインストールします。
プログラミング環境をまだアクティブ化していない場合は、プロジェクトディレクトリにいることを確認してください(flask_blog
)そして、次のコマンドを使用して環境をアクティブ化します。
- source env/bin/activate
プログラミング環境がアクティブ化されると、プロンプトに次のようになります。 env
次のように見えるプレフィックス:
-
このプレフィックスは、環境が env
は現在アクティブです。作成時に名前を付けた方法によっては、別の名前が付けられる場合があります。
注:バージョン管理システムである Git を使用して、プロジェクトの開発プロセスを効果的に管理および追跡できます。 Gitの使用方法については、Gitインストールの使用法とブランチの概要の記事をご覧ください。
Gitを使用している場合は、新しく作成されたものを無視することをお勧めします env
あなたのディレクトリ .gitignore
プロジェクトに関係のないファイルの追跡を避けるためのファイル。
次に、Pythonパッケージをインストールし、プロジェクトコードをメインのPythonシステムインストールから分離します。 これを使用して行います pip
と python
.
Flaskをインストールするには、次のコマンドを実行します。
- pip install flask
インストールが完了したら、次のコマンドを実行してインストールを確認します。
- python -c "import flask; print(flask.__version__)"
オプションを指定してpythonコマンドラインインターフェイスを使用します -c
Pythonコードを実行します。 次に、インポートします flask
とのパッケージ import flask;
次に、Flaskバージョンを印刷します。これは flask.__version__
変数。
出力は、次のようなバージョン番号になります。
Output1.1.2
プロジェクトフォルダ、仮想環境を作成し、Flaskをインストールしました。 これで、ベースアプリケーションのセットアップに進む準備ができました。
ステップ2—ベースアプリケーションの作成
プログラミング環境がセットアップされたので、Flaskの使用を開始します。 このステップでは、Pythonファイル内に小さなWebアプリケーションを作成し、それを実行してサーバーを起動します。これにより、ブラウザーにいくつかの情報が表示されます。
あなたの中で flask_blog
ディレクトリ、という名前のファイルを開きます hello.py
編集には、 nano
またはお気に入りのテキストエディタ:
- nano hello.py
これ hello.py
ファイルは、HTTPリクエストを処理する方法の最小限の例として機能します。 その中に、 Flaskオブジェクトをインポートし、HTTP応答を返す関数を作成します。 中に次のコードを書いてください hello.py
:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return 'Hello, World!'
上記のコードブロックでは、最初に Flask
からのオブジェクト flask
パッケージ。 次に、それを使用して、Flaskアプリケーションインスタンスを名前で作成します app
. 特別な変数を渡します __name__
これは、現在のPythonモジュールの名前を保持します。 これは、インスタンスにそれが配置されていることを伝えるために使用されます。これが必要なのは、Flaskが舞台裏でいくつかのパスを設定するためです。
作成したら app
たとえば、これを使用して、着信Web要求を処理し、ユーザーに応答を送信します。 @app.route
はデコレータであり、通常のPython関数をFlask ビュー関数に変換します。これにより、関数の戻り値がHTTP応答に変換され、WebブラウザなどのHTTPクライアントによって表示されます。 。 値を渡します '/'
に @app.route()
この関数がURLのWeb要求に応答することを示します /
、メインURLです。
The hello()
view関数は文字列を返します 'Hello, World!'
応答として。
ファイルを保存して閉じます。
Webアプリケーションを実行するには、最初にアプリケーションの場所をFlaskに指示します( hello.py
あなたの場合のファイル) FLASK_APP
環境変数:
- export FLASK_APP=hello
次に、開発モードで実行します。 FLASK_ENV
環境変数:
- export FLASK_ENV=development
最後に、を使用してアプリケーションを実行します flask run
指図:
- flask run
アプリケーションが実行されると、出力は次のようになります。
Output * Serving Flask app "hello" (lazy loading)
* Environment: development
* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 813-894-335
上記の出力には、次のようないくつかの情報が含まれています。
- 実行しているアプリケーションの名前。
- アプリケーションが実行されている環境。
Debug mode: on
Flaskデバッガーが実行されていることを示します。 これは、問題が発生したときに詳細なエラーメッセージが表示され、トラブルシューティングが容易になるため、開発時に役立ちます。- アプリケーションはURLでローカルに実行されています
http://127.0.0.1:5000/
,127.0.0.1
マシンを表すIPですlocalhost
と:5000
ポート番号です。
ブラウザを開き、URLを入力します http://127.0.0.1:5000/
、文字列を受け取ります Hello, World!
応答として、これはアプリケーションが正常に実行されていることを確認します。
警告Flaskは、シンプルなWebサーバーを使用して、開発環境でアプリケーションを提供します。これは、Flaskデバッガーが実行されているため、エラーの検出が容易になることも意味します。 この開発サーバーは、実稼働環境では使用しないでください。 詳細については、Flaskドキュメントの展開オプションページを参照してください。このFlask展開チュートリアルも確認できます。
これで、ターミナルで開発サーバーを実行したままにして、別のターミナルウィンドウを開くことができます。 プロジェクトフォルダに移動します。 hello.py
が見つかり、仮想環境をアクティブ化し、環境変数を設定します FLASK_ENV
と FLASK_APP
、次の手順に進みます。 (これらのコマンドは、このステップの前半にリストされています。)
注:新しい端末を開くときは、仮想環境のアクティブ化と環境変数の設定を覚えておくことが重要です。 FLASK_ENV
と FLASK_APP
.
Flaskアプリケーションの開発サーバーがすでに実行されている間は、同じもので別のFlaskアプリケーションを実行することはできません。 flask run
指図。 それの訳は flask run
ポート番号を使用します 5000
デフォルトでは、実行されると、別のアプリケーションを実行できなくなるため、次のようなエラーが発生します。
OutputOSError: [Errno 98] Address already in use
この問題を解決するには、現在実行中のサーバーを停止します。 CTRL+C
、次に実行します flask run
繰り返しますが、両方を同時に実行する場合は、別のポート番号をに渡すことができます -p
たとえば、ポートで別のアプリケーションを実行するための引数 5001
次のコマンドを使用します。
- flask run -p 5001
これで、小さなFlaskWebアプリケーションができました。 アプリケーションを実行し、Webブラウザに情報を表示しました。 次に、アプリケーションでHTMLファイルを使用します。
ステップ3—HTMLテンプレートを使用する
現在、アプリケーションはHTMLなしの単純なメッセージのみを表示します。 Webアプリケーションは主に訪問者向けの情報を表示するためにHTMLを使用するため、Webブラウザーに表示できるHTMLファイルをアプリに組み込む作業を行います。
フラスコは render_template()
Jinjaテンプレートエンジンを使用できるヘルパー関数。 これにより、HTMLコードをで記述して、HTMLの管理がはるかに簡単になります。 .html
ファイルだけでなく、HTMLコードでロジックを使用します。 これらのHTMLファイル( templates )を使用して、現在のブログ投稿を表示するメインページ、ブログ投稿のページ、次のページなど、すべてのアプリケーションページを作成します。ユーザーは新しい投稿を追加できます。
このステップでは、メインのFlaskアプリケーションを新しいファイルに作成します。
まず、あなたの flask_blog
ディレクトリ、使用 nano
または、お気に入りのエディタを作成および編集します app.py
ファイル。 これには、ブログアプリケーションの作成に使用するすべてのコードが含まれます。
- nano app.py
この新しいファイルでは、 Flask
以前に行ったようにFlaskアプリケーションインスタンスを作成するオブジェクト。 また、 render_template()ヘルパー関数をインポートして、に存在するHTMLテンプレートファイルをレンダリングできるようにします。 templates
作成しようとしているフォルダ。 ファイルには、メインへのリクエストの処理を担当する単一のビュー機能があります /
ルート。 次のコンテンツを追加します。
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
The index()
view関数は呼び出しの結果を返します render_template()
と index.html
議論として、これは render_template()
と呼ばれるファイルを探す index.html
templatesフォルダーにあります。 フォルダとファイルの両方がまだ存在していないため、この時点でアプリケーションを実行するとエラーが発生します。 それでも実行するので、この一般的に発生する例外に精通しています。 次に、必要なフォルダとファイルを作成して修正します。
ファイルを保存して終了します。
を実行している他の端末で開発サーバーを停止します hello
とのアプリケーション CTRL+C
.
アプリケーションを実行する前に、の値を正しく指定していることを確認してください FLASK_APP
アプリケーションを使用しなくなったため、環境変数 hello
:
- export FLASK_APP=app
- flask run
URLを開く http://127.0.0.1:5000/
ブラウザにあると、デバッガページに次のように通知されます。 index.html
テンプレートが見つかりませんでした。 このエラーの原因となったコードのメイン行が強調表示されます。 この場合、それはラインです return render_template('index.html')
.
この行をクリックすると、デバッガーによってより多くのコードが表示されるため、問題の解決に役立つコンテキストが増えます。
このエラーを修正するには、というディレクトリを作成します templates
あなたの中に flask_blog
ディレクトリ。 次に、その中に、というファイルを開きます index.html
編集用:
- mkdir templates
- nano templates/index.html
次に、次のHTMLコードを内部に追加します index.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>FlaskBlog</title>
</head>
<body>
<h1>Welcome to FlaskBlog</h1>
</body>
</html>
ファイルを保存し、ブラウザを使用してに移動します http://127.0.0.1:5000/
もう一度、またはページを更新してください。 今回はブラウザにテキストが表示されます Welcome to FlaskBlog
で <h1>
鬼ごっこ。
に加えて templates
フォルダ、FlaskWebアプリケーションにも通常は static
CSSファイル、JavaScriptファイル、アプリケーションが使用する画像などの静的ファイルをホストするためのフォルダー。
あなたは作成することができます style.css
アプリケーションにCSSを追加するためのスタイルシートファイル。 まず、というディレクトリを作成します static
メインの内側 flask_blog
ディレクトリ:
- mkdir static
次に、という別のディレクトリを作成します css
中 static
ホストするディレクトリ .css
ファイル。 これは通常、静的ファイルを専用フォルダーに整理するために行われます。JavaScriptファイルは通常、次のディレクトリ内にあります。 js
、画像はというディレクトリに配置されます images
(また img
)、 等々。 次のコマンドは、を作成します css
内部のディレクトリ static
ディレクトリ:
- mkdir static/css
次に、 style.css
内部のファイル css
編集用のディレクトリ:
- nano static/css/style.css
次のCSSルールをに追加します style.css
ファイル:
h1 {
border: 2px #eee solid;
color: brown;
text-align: center;
padding: 10px;
}
CSSコードは、境界線を追加し、色を茶色に変更し、テキストを中央に配置し、に少しパディングを追加します <h1>
タグ。
ファイルを保存して閉じます。
次に、 index.html
編集用のテンプレートファイル:
- nano templates/index.html
リンクを追加します style.css
内部のファイル <head>
のセクション index.html
テンプレートファイル:
. . .
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="{{ url_for('static', filename= 'css/style.css') }}">
<title>FlaskBlog</title>
</head>
. . .
ここでは、 url_for()ヘルパー関数を使用して、ファイルの適切な場所を生成します。 最初の引数は静的ファイルにリンクしていることを指定し、2番目の引数は静的ディレクトリ内のファイルのパスです。
ファイルを保存して閉じます。
アプリケーションのインデックスページを更新すると、テキストが表示されます。 Welcome to FlaskBlog
茶色になり、中央に配置され、境界線で囲まれています。
CSS言語を使用してアプリケーションのスタイルを設定し、独自のデザインを使用してアプリケーションをより魅力的にすることができます。 ただし、Webデザイナーでない場合、またはCSSに慣れていない場合は、 Bootstrapツールキットを使用できます。このツールキットは、アプリケーションのスタイルを設定するための使いやすいコンポーネントを提供します。 このプロジェクトでは、Bootstrapを使用します。
別のHTMLテンプレートを作成するということは、すでに作成したHTMLコードのほとんどを繰り返すことを意味すると推測したかもしれません。 index.html
テンプレート。 すべてのHTMLファイルが継承するベーステンプレートファイルを使用すると、不要なコードの繰り返しを回避できます。 詳細については、Jinjaでのテンプレートの継承を参照してください。
基本テンプレートを作成するには、最初にというファイルを作成します base.html
あなたの中に templates
ディレクトリ:
- nano templates/base.html
次のコードを入力します base.html
テンプレート:
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<title>{% block title %} {% endblock %}</title>
</head>
<body>
<nav class="navbar navbar-expand-md navbar-light bg-light">
<a class="navbar-brand" href="{{ url_for('index')}}">FlaskBlog</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item active">
<a class="nav-link" href="#">About</a>
</li>
</ul>
</div>
</nav>
<div class="container">
{% block content %} {% endblock %}
</div>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</body>
</html>
編集が完了したら、ファイルを保存して閉じます。
前のブロックのコードのほとんどは、標準のHTMLであり、Bootstrapに必要なコードです。 The <meta>
タグは、Webブラウザの情報を提供します。 <link>
タグはブートストラップCSSファイルとリンクします <script>
タグは、いくつかの追加のブートストラップ機能を可能にするJavaScriptコードへのリンクです。詳細については、ブートストラップドキュメントを確認してください。
ただし、以下の強調表示されている部分は、Jinjaテンプレートエンジンに固有のものです。
{% block title %} {% endblock %}
:タイトルのプレースホルダーとして機能するブロック。後で他のテンプレートで使用して、全体を書き直すことなく、アプリケーションの各ページにカスタムタイトルを付けることができます。<head>
毎回セクション。{{ url_for('index')}}
:のURLを返す関数呼び出しindex()
ビュー機能。 これは過去とは異なりますurl_for()
静的CSSファイルをリンクするために使用した呼び出し。これは、ビュー関数の名前である1つの引数のみを取り、静的ファイルではなく関数に関連付けられたルートにリンクするためです。{% block content %} {% endblock %}
:子テンプレート(から継承するテンプレート)に応じてコンテンツに置き換えられる別のブロックbase.html
)それを上書きします。
基本テンプレートができたので、継承を使用してそれを利用できます。 を開きます index.html
ファイル:
- nano templates/index.html
次に、その内容を次のように置き換えます。
{% extends 'base.html' %}
{% block content %}
<h1>{% block title %} Welcome to FlaskBlog {% endblock %}</h1>
{% endblock %}
この新しいバージョンでは index.html
テンプレート、あなたは使用します {% extends %}
から継承するタグ base.html
テンプレート。 次に、を置き換えることによってそれを拡張します content
基本テンプレートのブロックとその内部にあるもの content
前のコードブロックのブロック。
これ content
ブロックには <h1>
テキストでタグ付け Welcome to FlaskBlog
中 title
ブロックは、元のブロックを順番に置き換えます title
のブロック base.html
テキスト付きのテンプレート Welcome to FlaskBlog
. このように、同じテキストが2回繰り返されるのを避けることができます。これは、ページのタイトルと、ベーステンプレートから継承されたナビゲーションバーの下に表示される見出しの両方として機能するためです。
テンプレートの継承により、他のテンプレートにあるHTMLコードを再利用することもできます(base.html
この場合)必要になるたびに繰り返す必要はありません。
ファイルを保存して閉じ、ブラウザのインデックスページを更新します。 ナビゲーションバーとスタイル付きのタイトルが付いたページが表示されます。
FlaskでHTMLテンプレートと静的ファイルを使用しました。 また、Bootstrapを使用して、コードの繰り返しを回避するためにページとベーステンプレートの外観の調整を開始しました。 次のステップでは、アプリケーションデータを保存するデータベースを設定します。
ステップ4—データベースのセットアップ
このステップでは、データ、つまりアプリケーションのブログ投稿を保存するためのデータベースを設定します。 また、データベースにいくつかのエントリ例を入力します。
SQLiteデータベースファイルを使用してデータを保存します。これは、データベースとの対話に使用する sqlite3 モジュールが、標準のPythonライブラリですぐに利用できるためです。 SQLiteの詳細については、このチュートリアルをご覧ください。
まず、SQLiteのデータはテーブルと列に格納され、データは主にブログ投稿で構成されているため、最初に次のテーブルを作成する必要があります。 posts
必要な列で。 作成します .sql
を作成するためのSQLコマンドを含むファイル posts
いくつかの列を持つテーブル。 次に、このファイルを使用してデータベースを作成します。
というファイルを開きます schema.sql
あなたの中に flask_blog
ディレクトリ:
- nano schema.sql
このファイル内に次のSQLコマンドを入力します。
DROP TABLE IF EXISTS posts;
CREATE TABLE posts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
title TEXT NOT NULL,
content TEXT NOT NULL
);
ファイルを保存して閉じます。
最初のSQLコマンドは DROP TABLE IF EXISTS posts;
、これにより、という名前の既存のテーブルが削除されます posts
したがって、混乱する動作は発生しません。 これにより、これらのSQLコマンドを使用するたびにデータベースにあるすべてのコンテンツが削除されるため、このチュートリアルを終了して最終結果を試すまで、Webアプリケーションに重要なコンテンツを書き込まないようにしてください。 次、 CREATE TABLE posts
を作成するために使用されます posts
次の列を持つテーブル:
id
:主キーを表す整数。これには、各エントリ(ブログ投稿)のデータベースによって一意の値が割り当てられます。created
:ブログ投稿が作成された時刻。NOT NULL
この列が空であってはならず、DEFAULT
値はCURRENT_TIMESTAMP
値。投稿がデータベースに追加された時刻です。 と同じようにid
、この列の値は自動的に入力されるため、指定する必要はありません。title
:投稿のタイトル。content
:投稿内容。
これで、SQLスキーマが schema.sql
ファイルの場合、SQLiteを生成するPythonファイルを使用してデータベースを作成するために使用します .db
データベースファイル。 名前の付いたファイルを開きます init_db.py
中 flask_blog
お好みのエディタを使用したディレクトリ:
- nano init_db.py
次に、次のコードを追加します。
import sqlite3
connection = sqlite3.connect('database.db')
with open('schema.sql') as f:
connection.executescript(f.read())
cur = connection.cursor()
cur.execute("INSERT INTO posts (title, content) VALUES (?, ?)",
('First Post', 'Content for the first post')
)
cur.execute("INSERT INTO posts (title, content) VALUES (?, ?)",
('Second Post', 'Content for the second post')
)
connection.commit()
connection.close()
最初にインポートします sqlite3
モジュールを開き、という名前のデータベースファイルへの接続を開きます database.db
、Pythonファイルを実行すると作成されます。 次に、 open()
開く機能 schema.sql
ファイル。 次に、複数のSQLステートメントを一度に実行する executescript()メソッドを使用してコンテンツを実行します。これにより、 posts
テーブル。 カーソルオブジェクトを作成します。これにより、 execute()メソッドを使用して2つを実行できます。 INSERT
2つのブログ投稿を追加するSQLステートメント posts
テーブル。 最後に、変更をコミットして接続を閉じます。
ファイルを保存して閉じてから、を使用してターミナルで実行します。 python
指図:
- python init_db.py
ファイルの実行が完了すると、 database.db
あなたに表示されます flask_blog
ディレクトリ。 これは、データベースが正常にセットアップされたことを意味します。
次のステップでは、データベースに挿入した投稿を取得して、アプリケーションのホームページに表示します。
ステップ5—すべての投稿を表示する
データベースを設定したので、次の変更を行うことができます。 index()
データベースにあるすべての投稿を表示するビュー機能。
を開きます app.py
次の変更を行うファイル:
- nano app.py
最初の変更では、 sqlite3
ファイルの先頭にあるモジュール:
import sqlite3
from flask import Flask, render_template
. . .
次に、データベース接続を作成して返す関数を作成します。 インポートの直後に追加します。
. . .
from flask import Flask, render_template
def get_db_connection():
conn = sqlite3.connect('database.db')
conn.row_factory = sqlite3.Row
return conn
. . .
これ get_db_connection()
関数はへの接続を開きます database.db
データベースファイルを作成し、row_factory属性を次のように設定します。 sqlite3.Row
そのため、名前に基づいて列にアクセスできます。 これは、データベース接続が通常のPythonディクショナリのように動作する行を返すことを意味します。 最後に、関数は conn
データベースへのアクセスに使用する接続オブジェクト。
定義した後 get_db_connection()
関数、変更 index()
次のように見える関数:
. . .
@app.route('/')
def index():
conn = get_db_connection()
posts = conn.execute('SELECT * FROM posts').fetchall()
conn.close()
return render_template('index.html', posts=posts)
この新しいバージョンでは index()
関数では、最初にデータベース接続を使用してデータベース接続を開きます get_db_connection()
前に定義した関数。 次に、SQLクエリを実行して、からすべてのエントリを選択します。 posts
テーブル。 fetchall()メソッドを実装して、クエリ結果のすべての行をフェッチします。これにより、前の手順でデータベースに挿入した投稿のリストが返されます。
を使用してデータベース接続を閉じます close()
メソッドとレンダリングの結果を返します index.html
テンプレート。 あなたも合格します posts
データベースから取得した結果を含む引数としてのオブジェクト。これにより、 index.html
テンプレート。
これらの変更を行ったら、保存して閉じます app.py
ファイル。
これで、データベースからフェッチした投稿を index.html
テンプレートでは、 for loop を使用して、インデックスページに各投稿を表示できます。
を開きます index.html
ファイル:
- nano templates/index.html
次に、次のように変更します。
{% extends 'base.html' %}
{% block content %}
<h1>{% block title %} Welcome to FlaskBlog {% endblock %}</h1>
{% for post in posts %}
<a href="#">
<h2>{{ post['title'] }}</h2>
</a>
<span class="badge badge-primary">{{ post['created'] }}</span>
<hr>
{% endfor %}
{% endblock %}
ここで、構文 {% for post in posts %}
ジンジャです for
Pythonに似たループ for
後でループを閉じる必要があることを除いて、ループ {% endfor %}
構文。 この構文を使用して、 posts
によって渡されたリスト index()
行の関数 return render_template('index.html', posts=posts)
. この中 for
ループ、投稿タイトルを <h2>
中へ向かう <a>
タグ(後でこのタグを使用して、各投稿に個別にリンクします)。
リテラル変数区切り文字を使用してタイトルを表示します({{ ... }}
). それを覚えておいてください post
辞書のようなオブジェクトになるので、次のコマンドで投稿のタイトルにアクセスできます post['title']
. 同じ方法で投稿の作成日も表示します。
ファイルの編集が完了したら、ファイルを保存して閉じます。 次に、ブラウザのインデックスページに移動します。 ページにデータベースに追加した2つの投稿が表示されます。
これで、 index()
アプリケーションのホームページのデータベースにあるすべての投稿を表示するビュー機能では、各投稿を1つのページに表示し、ユーザーが個々の投稿にリンクできるようにします。
ステップ6—単一の投稿を表示する
このステップでは、表示機能と新しいHTMLテンプレートを使用して新しいFlaskルートを作成し、IDで個々のブログ投稿を表示します。
このステップの終わりまでに、URL http://127.0.0.1:5000/1
最初の投稿を表示するページになります(IDがあるため) 1
). The http://127.0.0.1:5000/ID
URLには、関連付けられた投稿が表示されます ID
存在する場合は番号。
開ける app.py
編集用:
- nano app.py
このプロジェクトの後半では、複数の場所にあるデータベースからIDでブログ投稿を取得する必要があるため、次のようなスタンドアロン関数を作成します。 get_post()
. IDを渡して、提供されたIDに関連付けられたブログ投稿を受け取ることで呼び出すか、Flaskに応答させることができます。 404 Not Found
ブログ投稿が存在しない場合のメッセージ。
で応答するには 404
このページでは、Flaskと一緒にインストールされた Werkzeugライブラリからabort()関数をファイルの先頭にインポートする必要があります。
import sqlite3
from flask import Flask, render_template
from werkzeug.exceptions import abort
. . .
次に、 get_post()
直後に機能する get_db_connection()
前の手順で作成した関数:
. . .
def get_db_connection():
conn = sqlite3.connect('database.db')
conn.row_factory = sqlite3.Row
return conn
def get_post(post_id):
conn = get_db_connection()
post = conn.execute('SELECT * FROM posts WHERE id = ?',
(post_id,)).fetchone()
conn.close()
if post is None:
abort(404)
return post
. . .
この新しい関数には post_id
返すブログ投稿を決定する引数。
関数内では、 get_db_connection()
データベース接続を開き、SQLクエリを実行して、指定されたブログ投稿に関連付けられたブログ投稿を取得する関数 post_id
価値。 追加します fetchone()
結果を取得してに保存するメソッド post
次に、変数を使用して接続を閉じます。 の場合 post
変数の値は None
、データベースに結果が見つからなかったことを意味します。 abort()
以前にインポートした関数で応答します 404
エラーコードと関数は実行を終了します。 ただし、投稿が見つかった場合は、の値を返します post
変数。
次に、最後に次のビュー関数を追加します app.py
ファイル:
. . .
@app.route('/<int:post_id>')
def post(post_id):
post = get_post(post_id)
return render_template('post.html', post=post)
この新しいビュー関数では、変数ルールを追加します <int:post_id>
スラッシュの後の部分を指定するには(/
)は正の整数です( int
コンバーター)ビュー関数でアクセスする必要があります。 Flaskはこれを認識し、その値を post_id
あなたのキーワード引数 post()
ビュー機能。 次に、 get_post()
指定されたIDに関連付けられたブログ投稿を取得し、結果を post
に渡す変数 post.html
すぐに作成するテンプレート。
を助けて app.py
ファイルを作成して新しい post.html
編集用のテンプレートファイル:
- nano templates/post.html
この新しいコードに次のコードを入力します post.html
ファイル。 これは、 index.html
投稿の内容も表示することに加えて、単一の投稿のみを表示することを除いて、ファイル:
{% extends 'base.html' %}
{% block content %}
<h2>{% block title %} {{ post['title'] }} {% endblock %}</h2>
<span class="badge badge-primary">{{ post['created'] }}</span>
<p>{{ post['content'] }}</p>
{% endblock %}
追加します title
で定義したブロック base.html
ページのタイトルに、に表示される投稿のタイトルを反映させるためのテンプレート <h2>
同時に見出し。
ファイルを保存して閉じます。
これで、次のURLに移動して、データベースにある2つの投稿と、要求されたブログ投稿が見つからなかったことをユーザーに通知するページを表示できます(ID番号が 3
これまでのところ):
http://127.0.0.1:5000/1
http://127.0.0.1:5000/2
http://127.0.0.1:5000/3
インデックスページに戻ると、各投稿タイトルをそれぞれのページにリンクします。 これは、 url_for()
関数。 まず、 index.html
編集用のテンプレート:
- nano templates/index.html
次に、の値を変更します href
からの属性 #
に {{ url_for('post', post_id=post['id']) }}
そのため for
ループは次のようになります。
{% for post in posts %}
<a href="{{ url_for('post', post_id=post['id']) }}">
<h2>{{ post['title'] }}</h2>
</a>
<span class="badge badge-primary">{{ post['created'] }}</span>
<hr>
{% endfor %}
ここで、あなたは合格します 'post'
に url_for()
最初の引数として機能します。 これはの名前です post()
ビュー関数とそれが受け入れるので post_id
引数、あなたはそれに値を与えます post['id']
. The url_for()
関数は、IDに基づいて各投稿の適切なURLを返します。
ファイルを保存して閉じます。
インデックスページのリンクが期待どおりに機能するようになります。 これで、データベースにブログ投稿を表示するアプリケーションの一部の構築が完了しました。 次に、ブログ投稿を作成、編集、および削除する機能をアプリケーションに追加します。
ステップ7—投稿の変更
これで、データベースに存在するブログ投稿をWebアプリケーションに表示し終えたので、アプリケーションのユーザーが新しいブログ投稿を作成してデータベースに追加し、既存のブログ投稿を編集し、不要なものを削除できるようにする必要があります。ブログ投稿。
新しい投稿を作成する
これまでのところ、データベース内の投稿を表示するアプリケーションがありますが、SQLiteデータベースに直接接続して手動で追加しない限り、新しい投稿を追加する方法はありません。 このセクションでは、タイトルとコンテンツを指定して投稿を作成できるページを作成します。
を開きます app.py
編集用ファイル:
- nano app.py
まず、Flaskフレームワークから以下をインポートします。
- HTMLフォームを介して送信される着信リクエストデータにアクセスするためのグローバルrequestオブジェクト。
- url_for()関数を使用してURLを生成します。
- flash()関数は、リクエストの処理時にメッセージをフラッシュします。
- クライアントを別の場所にリダイレクトするredirect()関数。
次のように、インポートをファイルに追加します。
import sqlite3
from flask import Flask, render_template, request, url_for, flash, redirect
from werkzeug.exceptions import abort
. . .
The flash()
関数は、フラッシュされたメッセージをクライアントのブラウザセッションに保存します。これには、秘密鍵を設定する必要があります。 この秘密鍵はセッションを保護するために使用されます。これにより、Flaskは、新しい投稿ページからインデックスページへの移動など、あるリクエストから別のリクエストへの情報を記憶できます。 ユーザーはセッションに保存されている情報にアクセスできますが、秘密鍵を持っていない限り変更することはできません。そのため、誰にも秘密鍵へのアクセスを許可してはなりません。 詳細については、セッションのFlaskドキュメントを参照してください。
秘密鍵を設定するには、 SECRET_KEY
を介したアプリケーションへの構成 app.config
物体。 次の直後に追加します app
定義する前の定義 index()
ビュー機能:
. . .
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your secret key'
@app.route('/')
def index():
conn = get_db_connection()
posts = conn.execute('SELECT * FROM posts').fetchall()
conn.close()
return render_template('index.html', posts=posts)
. . .
秘密鍵は長いランダムな文字列である必要があることに注意してください。
秘密鍵を設定した後、新しいブログ投稿を作成するために入力できるフォームを表示するテンプレートをレンダリングするビュー関数を作成します。 ファイルの最後に次の新しい関数を追加します。
. . .
@app.route('/create', methods=('GET', 'POST'))
def create():
return render_template('create.html')
これにより、 /create
GETリクエストとPOSTリクエストの両方を受け入れるルート。 GETリクエストはデフォルトで受け入れられます。 フォームの送信時にブラウザから送信されるPOSTリクエストも受け入れるには、受け入れられたタイプのリクエストを含むタプルを methods
の引数 @app.route()
デコレータ。
ファイルを保存して閉じます。
テンプレートを作成するには、というファイルを開きます create.html
あなたの中に templates
フォルダ:
- nano templates/create.html
この新しいファイル内に次のコードを追加します。
{% extends 'base.html' %}
{% block content %}
<h1>{% block title %} Create a New Post {% endblock %}</h1>
<form method="post">
<div class="form-group">
<label for="title">Title</label>
<input type="text" name="title"
placeholder="Post title" class="form-control"
value="{{ request.form['title'] }}"></input>
</div>
<div class="form-group">
<label for="content">Content</label>
<textarea name="content" placeholder="Post content"
class="form-control">{{ request.form['content'] }}</textarea>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
{% endblock %}
このコードのほとんどは標準のHTMLです。 投稿タイトルの入力ボックス、投稿コンテンツのテキスト領域、およびフォームを送信するためのボタンが表示されます。
投稿タイトル入力の値は次のとおりです。 {{ request.form['title'] }}
テキスト領域には値があります {{ request.form['content'] }}
、これは、何か問題が発生した場合に入力したデータが失われないようにするために行われます。 たとえば、長い投稿を書いたときにタイトルを付けるのを忘れた場合、タイトルが必要であることを通知するメッセージが表示されます。 これは、あなたが書いた投稿を失うことなく起こります。 request
テンプレートでアクセスできるグローバルオブジェクト。
これで、開発サーバーが実行されている状態で、ブラウザーを使用してに移動します。 /create
ルート:
http://127.0.0.1:5000/create
タイトルとコンテンツのボックスが表示された新しい投稿の作成ページが表示されます。
このフォームはPOSTリクエストをあなたに送信します create()
ビュー機能。 ただし、関数にはPOSTリクエストを処理するコードがまだないため、フォームに入力して送信しても何も起こりません。
フォームが送信されたときに、着信POSTリクエストを処理します。 あなたは内部でこれを行います create()
ビュー機能。 の値を確認することで、POSTリクエストを個別に処理できます。 request.method
. その値がに設定されている場合 'POST'
これは、リクエストがPOSTリクエストであることを意味します。次に、送信されたデータの抽出、検証、データベースへの挿入に進みます。
を開きます app.py
編集用ファイル:
- nano app.py
を変更します create()
次のように正確に見える関数を表示します。
. . .
@app.route('/create', methods=('GET', 'POST'))
def create():
if request.method == 'POST':
title = request.form['title']
content = request.form['content']
if not title:
flash('Title is required!')
else:
conn = get_db_connection()
conn.execute('INSERT INTO posts (title, content) VALUES (?, ?)',
(title, content))
conn.commit()
conn.close()
return redirect(url_for('index'))
return render_template('create.html')
の中に if
それに続くコードが、比較によるPOSTリクエストである場合にのみ実行されることを確認するステートメント request.method == 'POST'
.
次に、送信されたタイトルとコンテンツを request.form
リクエスト内のフォームデータへのアクセスを提供するオブジェクト。 タイトルが提供されていない場合、条件 if not title
タイトルが必要であることをユーザーに通知するメッセージを表示して、実行されます。 一方、タイトルが提供されている場合は、 get_db_connection()
機能し、受け取ったタイトルとコンテンツをに挿入します posts
テーブル。
次に、データベースへの変更をコミットし、接続を閉じます。 ブログ投稿をデータベースに追加した後、を使用してクライアントをインデックスページにリダイレクトします。 redirect()
によって生成されたURLを渡す関数 url_for()
値を持つ関数 'index'
引数として。
ファイルを保存して閉じます。
次に、に移動します /create
Webブラウザを使用してルーティングします。
http://127.0.0.1:5000/create
選択したタイトルといくつかのコンテンツをフォームに入力します。 フォームを送信すると、インデックスページに新しい投稿が表示されます。
最後に、フラッシュされたメッセージを表示し、ナビゲーションバーへのリンクを追加します base.html
この新しいページに簡単にアクセスできるテンプレート。 テンプレートファイルを開きます。
- nano templates/base.html
新しいファイルを追加してファイルを編集します <li>
次のタグ About
内部のリンク <nav>
鬼ごっこ。 次に、新しいを追加します for
真上でループする content
ナビゲーションバーの下に点滅するメッセージを表示するには、ブロックします。 これらのメッセージは特別に利用可能です get_flashed_messages()
Flaskが提供する機能:
<nav class="navbar navbar-expand-md navbar-light bg-light">
<a class="navbar-brand" href="{{ url_for('index')}}">FlaskBlog</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="#">About</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{url_for('create')}}">New Post</a>
</li>
</ul>
</div>
</nav>
<div class="container">
{% for message in get_flashed_messages() %}
<div class="alert alert-danger">{{ message }}</div>
{% endfor %}
{% block content %} {% endblock %}
</div>
ファイルを保存して閉じます。 ナビゲーションバーに New Post
にリンクするアイテム /create
ルート。
投稿の編集
ブログを最新の状態にするには、既存の投稿を編集できる必要があります。 このセクションでは、投稿を編集するプロセスを簡素化するために、アプリケーションで新しいページを作成する方法について説明します。
まず、新しいルートをに追加します app.py
ファイル。 その表示機能は、編集が必要な投稿のIDを受け取り、URLは次の形式になります /post_id/edit
とともに post_id
変数は投稿のIDです。 を開きます app.py
編集用ファイル:
- nano app.py
次に、以下を追加します edit()
ファイルの最後にあるview関数。 既存の投稿の編集は新しい投稿の作成に似ているため、この表示機能は create()
ビュー機能:
. . .
@app.route('/<int:id>/edit', methods=('GET', 'POST'))
def edit(id):
post = get_post(id)
if request.method == 'POST':
title = request.form['title']
content = request.form['content']
if not title:
flash('Title is required!')
else:
conn = get_db_connection()
conn.execute('UPDATE posts SET title = ?, content = ?'
' WHERE id = ?',
(title, content, id))
conn.commit()
conn.close()
return redirect(url_for('index'))
return render_template('edit.html', post=post)
編集する投稿はURLによって決定され、FlaskはID番号を edit()
を介して機能 id
口論。 この値をに追加します get_post()
指定されたIDに関連付けられた投稿をデータベースからフェッチする関数。 新しいデータはPOSTリクエストで送信され、POSTリクエスト内で処理されます。 if request.method == 'POST'
調子。
新しい投稿を作成するときと同じように、最初にデータを抽出します request.form
次に、タイトルに空の値がある場合はオブジェクトがメッセージをフラッシュします。それ以外の場合は、データベース接続を開きます。 次に、を更新します posts
データベース内の投稿のIDがURL内にあったIDと等しい新しいタイトルと新しいコンテンツを設定することにより、テーブルを作成します。
GETリクエストの場合、レンダリングします edit.html
テンプレートを渡す post
の戻り値を保持する変数 get_post()
関数。 これを使用して、編集ページに既存のタイトルとコンテンツを表示します。
ファイルを保存して閉じてから、新しいファイルを作成します edit.html
テンプレート:
- nano templates/edit.html
この新しいファイル内に次のコードを記述します。
{% extends 'base.html' %}
{% block content %}
<h1>{% block title %} Edit "{{ post['title'] }}" {% endblock %}</h1>
<form method="post">
<div class="form-group">
<label for="title">Title</label>
<input type="text" name="title" placeholder="Post title"
class="form-control"
value="{{ request.form['title'] or post['title'] }}">
</input>
</div>
<div class="form-group">
<label for="content">Content</label>
<textarea name="content" placeholder="Post content"
class="form-control">{{ request.form['content'] or post['content'] }}</textarea>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
<hr>
{% endblock %}
ファイルを保存して閉じます。
このコードは、 {{ request.form['title'] or post['title'] }}
と {{ request.form['content'] or post['content'] }}
構文。 これにより、リクエストに保存されているデータが存在する場合は表示され、存在しない場合は、 post
現在のデータベースデータを含むテンプレートに渡された変数。
次に、次のURLに移動して、最初の投稿を編集します。
http://127.0.0.1:5000/1/edit
「最初の投稿」の編集ページが表示されます。
投稿を編集してフォームを送信し、投稿が更新されたことを確認します。
次に、インデックスページの各投稿の編集ページを指すリンクを追加する必要があります。 を開きます index.html
テンプレートファイル:
- nano templates/index.html
次のようにファイルを編集します。
{% extends 'base.html' %}
{% block content %}
<h1>{% block title %} Welcome to FlaskBlog {% endblock %}</h1>
{% for post in posts %}
<a href="{{ url_for('post', post_id=post['id']) }}">
<h2>{{ post['title'] }}</h2>
</a>
<span class="badge badge-primary">{{ post['created'] }}</span>
<a href="{{ url_for('edit', id=post['id']) }}">
<span class="badge badge-warning">Edit</span>
</a>
<hr>
{% endfor %}
{% endblock %}
ファイルを保存して閉じます。
ここに追加します <a>
リンクするタグ edit()
ビュー関数、渡して post['id']
各投稿の編集ページにリンクする値 Edit
リンク。
投稿の削除
投稿を公開する必要がなくなる場合があります。そのため、投稿を削除する機能が重要になります。 このステップでは、アプリケーションに削除機能を追加します。
まず、新しいものを追加します /ID/delete
POSTリクエストを受け入れるルート。 edit()
ビュー機能。 あなたの新しい delete()
ビュー機能は、URLから削除する投稿のIDを受け取ります。 を開きます app.py
ファイル:
- nano app.py
ファイルの下部に次のビュー関数を追加します。
# ....
@app.route('/<int:id>/delete', methods=('POST',))
def delete(id):
post = get_post(id)
conn = get_db_connection()
conn.execute('DELETE FROM posts WHERE id = ?', (id,))
conn.commit()
conn.close()
flash('"{}" was successfully deleted!'.format(post['title']))
return redirect(url_for('index'))
このビュー関数は、POST要求のみを受け入れます。 これは、 /ID/delete
WebブラウザはデフォルトでGETリクエストを使用しているため、ブラウザのルートはエラーを返します。
ただし、削除する投稿のIDを渡すPOSTリクエストを送信するフォームを介して、このルートにアクセスできます。 この関数はID値を受け取り、それを使用してデータベースから投稿を取得します。 get_post()
関数。
次に、データベース接続を開き、 DELETE FROM
投稿を削除するSQLコマンド。 データベースへの変更をコミットし、メッセージをフラッシュしながら接続を閉じて、投稿が正常に削除されたことをユーザーに通知し、インデックスページにリダイレクトします。
テンプレートファイルをレンダリングしないことに注意してください。これは、追加するだけだからです。 Delete
編集ページへのボタン。
を開きます edit.html
テンプレートファイル:
- nano templates/edit.html
次に、以下を追加します <form>
後のタグ <hr>
タグとその直前 {% endblock %}
ライン:
<hr>
<form action="{{ url_for('delete', id=post['id']) }}" method="POST">
<input type="submit" value="Delete Post"
class="btn btn-danger btn-sm"
onclick="return confirm('Are you sure you want to delete this post?')">
</form>
{% endblock %}
confirm()メソッドを使用して、リクエストを送信する前に確認メッセージを表示します。
次に、ブログ投稿の編集ページに再度移動して、削除してみます。
http://127.0.0.1:5000/1/edit
この手順を完了すると、プロジェクトのソースコードはこのページのコードのようになります。
これにより、アプリケーションのユーザーは、新しいブログ投稿を作成してデータベースに追加したり、既存の投稿を編集および削除したりできるようになります。
結論
このチュートリアルでは、FlaskPythonフレームワークの基本的な概念を紹介しました。 小さなWebアプリケーションを作成し、それを開発サーバーで実行し、ユーザーがURLパラメーターとWebフォームを介してカスタムデータを提供できるようにする方法を学びました。 また、 Jinjaテンプレートエンジンを使用してHTMLファイルを再利用し、その中でロジックを使用しました。 このチュートリアルを終了すると、 SQLiteデータベースと対話して、Python言語とSQLクエリを使用してブログ投稿を作成、表示、編集、および削除する、完全に機能するWebブログができました。 FlaskとSQLiteの操作について詳しく知りたい場合は、FlaskとSQLiteで1対多のデータベース関係を使用する方法に関するこのチュートリアルを確認してください。
登録ユーザーのみがブログ投稿を作成および変更できるようにユーザー認証を追加することで、このアプリケーションをさらに開発できます。また、各ブログ投稿にコメントとタグを追加し、ファイルアップロードを追加して、ユーザーが投稿に画像を含めることができるようにすることもできます。 詳細については、Flaskのドキュメントを参照してください。
Flaskには、コミュニティで作成されたFlask拡張機能が多数あります。 以下は、開発プロセスを容易にするために使用を検討する可能性のある拡張機能のリストです。
- Flask-Login :ユーザーセッションを管理し、ログインとログアウト、およびログインしたユーザーの記憶を処理します。
- Flask-SQLAlchemy :SQLデータベースと対話するためのPythonSQLツールキットおよびオブジェクトリレーショナルマッパーであるSQLAlchemyでFlaskを使用することを簡素化します。
- Flask-Mail :Flaskアプリケーションで電子メールメッセージを送信するタスクを支援します。