Python3でFlaskを使用してWebアプリケーションを作成する方法
著者は、 Write for DOnations プログラムの一環として、 Free and Open SourceFundを選択して寄付を受け取りました。
序章
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を使用している場合は、プロジェクトに関係のないファイルを追跡しないように、.gitignoreファイルに新しく作成されたenvディレクトリを無視することをお勧めします。
次に、Pythonパッケージをインストールし、プロジェクトコードをメインのPythonシステムインストールから分離します。 これは、pipおよびpythonを使用して行います。
Flaskをインストールするには、次のコマンドを実行します。
pip install flask
インストールが完了したら、次のコマンドを実行してインストールを確認します。
python -c "import flask; print(flask.__version__)"
pythonコマンドラインインターフェイスとオプション-cを使用して、Pythonコードを実行します。 次に、flaskパッケージをimport flask;とともにインポートし、flask.__version__変数を介して提供されるFlaskバージョンを印刷します。
出力は、次のようなバージョン番号になります。
Output1.1.2
プロジェクトフォルダ、仮想環境を作成し、Flaskをインストールしました。 これで、ベースアプリケーションのセットアップに進む準備ができました。
ステップ2—ベースアプリケーションの作成
プログラミング環境がセットアップされたので、Flaskの使用を開始します。 このステップでは、Pythonファイル内に小さなWebアプリケーションを作成し、それを実行してサーバーを起動します。これにより、ブラウザーにいくつかの情報が表示されます。
flask_blogディレクトリで、hello.pyという名前のファイルを開いて編集し、nanoまたはお気に入りのテキストエディタを使用します。
nano hello.py
このhello.pyファイルは、HTTPリクエストを処理する方法の最小限の例として機能します。 その中に、 Flaskオブジェクトをインポートし、HTTP応答を返す関数を作成します。 hello.py内に次のコードを記述します。
フラスコブログ/hello.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return 'Hello, World!'
上記のコードブロックでは、最初にFlaskオブジェクトをflaskパッケージからインポートします。 次に、それを使用して、appという名前のFlaskアプリケーションインスタンスを作成します。 現在のPythonモジュールの名前を保持する特別な変数__name__を渡します。 これは、インスタンスにそれが配置されていることを伝えるために使用されます。これが必要なのは、Flaskが舞台裏でいくつかのパスを設定するためです。
appインスタンスを作成したら、それを使用して着信Web要求を処理し、ユーザーに応答を送信します。 @app.routeはデコレータであり、通常のPython関数をFlask ビュー関数に変換します。これにより、関数の戻り値がHTTP応答に変換されてHTTPクライアントで表示されます。 、Webブラウザなど。 値'/'を@app.route()に渡して、この関数がメインURLであるURL/に対するWeb要求に応答することを示します。
hello()ビュー関数は、文字列'Hello, World!'を応答として返します。
ファイルを保存して閉じます。
Webアプリケーションを実行するには、最初にFLASK_APP環境変数を使用してアプリケーション(この場合はhello.pyファイル)の場所をFlaskに指示します。
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はマシンのlocalhostを表すIPであり、: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 runコマンドで別のFlaskアプリケーションを実行することはできません。 これは、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ファイルをアプリに組み込む作業を行います。
Flaskは、Jinjaテンプレートエンジンの使用を可能にするrender_template()ヘルパー関数を提供します。 これにより、.htmlファイルにHTMLコードを記述したり、HTMLコードでロジックを使用したりすることで、HTMLの管理がはるかに簡単になります。 これらのHTMLファイル( templates )を使用して、現在のブログ投稿を表示するメインページ、ブログ投稿のページ、次のページなど、すべてのアプリケーションページを作成します。ユーザーは新しい投稿を追加できます。
このステップでは、メインのFlaskアプリケーションを新しいファイルに作成します。
まず、flask_blogディレクトリで、nanoまたはお気に入りのエディタを使用して、app.pyファイルを作成および編集します。 これには、ブログアプリケーションの作成に使用するすべてのコードが含まれます。
nano app.py
この新しいファイルでは、Flaskオブジェクトをインポートして、以前と同じようにFlaskアプリケーションインスタンスを作成します。 また、作成しようとしているtemplatesフォルダーに存在するHTMLテンプレートファイルをレンダリングできるrender_template()ヘルパー関数もインポートします。 このファイルには、メインの/ルートへのリクエストの処理を担当する単一のビュー機能があります。 次のコンテンツを追加します。
フラスコブログ/app.py
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
index()ビュー関数は、index.htmlを引数としてrender_template()を呼び出した結果を返します。これにより、render_template()はindex.htmlというファイルを検索するようになります。 ]テンプレートフォルダにあります。 フォルダとファイルの両方がまだ存在していないため、この時点でアプリケーションを実行するとエラーが発生します。 それでも実行するので、この一般的に発生する例外に精通しています。 次に、必要なフォルダとファイルを作成して修正します。
ファイルを保存して終了します。
CTRL+Cでhelloアプリケーションを実行している他の端末で開発サーバーを停止します。
アプリケーションを実行する前に、FLASK_APP環境変数の値を正しく指定していることを確認してください。これは、アプリケーションhelloを使用しなくなったためです。
export FLASK_APP=app flask run
ブラウザでURLhttp://127.0.0.1:5000/を開くと、index.htmlテンプレートが見つからなかったことがデバッガページに通知されます。 このエラーの原因となったコードのメイン行が強調表示されます。 この場合は、return render_template('index.html')の行です。
この行をクリックすると、デバッガーによってより多くのコードが表示されるため、問題の解決に役立つコンテキストが増えます。
このエラーを修正するには、flask_blogディレクトリ内にtemplatesというディレクトリを作成します。 次に、その中のindex.htmlというファイルを開いて編集します。
mkdir templates nano templates/index.html
次に、index.html内に次のHTMLコードを追加します。
フラスコ_ブログ/templates/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/に再度移動するか、ページを更新します。 今回は、ブラウザは<h1>タグにテキストWelcome to FlaskBlogを表示する必要があります。
templatesフォルダーに加えて、Flask Webアプリケーションには通常、CSSファイル、JavaScriptファイル、アプリケーションが使用する画像などの静的ファイルをホストするためのstaticフォルダーもあります。
style.cssスタイルシートファイルを作成して、CSSをアプリケーションに追加できます。 まず、メインのflask_blogディレクトリ内にstaticというディレクトリを作成します。
mkdir static
次に、staticディレクトリ内にcssという別のディレクトリを作成して、.cssファイルをホストします。 これは通常、静的ファイルを専用フォルダーに整理するために行われます。JavaScriptファイルは通常jsというディレクトリ内にあり、画像はimages(またはimgというディレクトリに配置されます。 ])、 等々。 次のコマンドは、staticディレクトリ内にcssディレクトリを作成します。
mkdir static/css
次に、cssディレクトリ内のstyle.cssファイルを開いて編集します。
nano static/css/style.css
次の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
index.htmlテンプレートファイルの<head>セクション内にstyle.cssファイルへのリンクを追加します。
フラスコ_ブログ/templates/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テンプレートを作成するということは、index.htmlテンプレートで既に記述したHTMLコードのほとんどを繰り返すことを意味すると推測したかもしれません。 すべてのHTMLファイルが継承するベーステンプレートファイルを使用すると、不要なコードの繰り返しを回避できます。 詳細については、Jinjaでのテンプレートの継承を参照してください。
基本テンプレートを作成するには、最初にtemplatesディレクトリ内にbase.htmlというファイルを作成します。
nano templates/base.html
base.htmlテンプレートに次のコードを入力します。
フラスコ_ブログ/templates/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に必要なコードです。 <meta>タグはWebブラウザーの情報を提供し、<link>タグはブートストラップCSSファイルをリンクし、<script>タグはいくつかの追加のブートストラップ機能を可能にするJavaScriptコードへのリンクです。詳細については、ブートストラップドキュメントを確認してください。
ただし、以下の強調表示されている部分は、Jinjaテンプレートエンジンに固有のものです。
{% block title %} {% endblock %}:タイトルのプレースホルダーとして機能するブロック。後で他のテンプレートで使用して、<head>セクションは毎回。テンプレート:Url for('index'):index()ビュー関数のURLを返す関数呼び出し。 これは、静的CSSファイルをリンクするために使用した過去のurl_for()呼び出しとは異なります。これは、ビュー関数の名前である1つの引数のみを取り、静的ファイルではなく関数に関連付けられたルートにリンクするためです。 。{% block content %} {% endblock %}:子テンプレート(base.htmlから継承するテンプレート)に応じてコンテンツに置き換えられる別のブロックで、それをオーバーライドします。
基本テンプレートができたので、継承を使用してそれを利用できます。 index.htmlファイルを開きます。
nano templates/index.html
次に、その内容を次のように置き換えます。
フラスコ_ブログ/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ブロックには、titleブロック内にテキストWelcome to FlaskBlogが含まれる<h1>タグが含まれています。これにより、元のtitleブロックが置き換えられます。 base.htmlテンプレートとテキストWelcome to FlaskBlog。 このように、同じテキストが2回繰り返されるのを避けることができます。これは、ページのタイトルと、ベーステンプレートから継承されたナビゲーションバーの下に表示される見出しの両方として機能するためです。
テンプレートの継承により、必要になるたびに繰り返すことなく、他のテンプレート(この場合はbase.html)にあるHTMLコードを再利用することもできます。
ファイルを保存して閉じ、ブラウザのインデックスページを更新します。 ナビゲーションバーとスタイル付きのタイトルが付いたページが表示されます。
FlaskでHTMLテンプレートと静的ファイルを使用しました。 また、Bootstrapを使用して、コードの繰り返しを回避するためにページとベーステンプレートの外観の調整を開始しました。 次のステップでは、アプリケーションデータを保存するデータベースを設定します。
ステップ4—データベースのセットアップ
このステップでは、データ、つまりアプリケーションのブログ投稿を保存するためのデータベースを設定します。 また、データベースにいくつかのエントリ例を入力します。
SQLiteデータベースファイルを使用してデータを保存します。これは、データベースとの対話に使用する sqlite3 モジュールが、標準のPythonライブラリですぐに利用できるためです。 SQLiteの詳細については、このチュートリアルをご覧ください。
まず、SQLiteのデータはテーブルと列に格納され、データは主にブログ投稿で構成されているため、最初に必要な列を含むpostsというテーブルを作成する必要があります。 SQLコマンドを含む.sqlファイルを作成して、いくつかの列を持つpostsテーブルを作成します。 次に、このファイルを使用してデータベースを作成します。
flask_blogディレクトリ内にあるschema.sqlというファイルを開きます。
nano schema.sql
このファイル内に次の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:投稿の内容。
schema.sqlファイルにSQLスキーマができたので、それを使用して、SQLite.dbデータベースファイルを生成するPythonファイルを使用してデータベースを作成します。 お好みのエディタを使用して、flask_blogディレクトリ内のinit_db.pyという名前のファイルを開きます。
nano init_db.py
次に、次のコードを追加します。
フラスコ_ブログ/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モジュールをインポートしてから、Pythonファイルを実行すると作成されるdatabase.dbという名前のデータベースファイルへの接続を開きます。 次に、open()関数を使用して、schema.sqlファイルを開きます。 次に、複数のSQLステートメントを一度に実行する executescript()メソッドを使用してその内容を実行します。これにより、postsテーブルが作成されます。 カーソルオブジェクトを作成します。これにより、 execute()メソッドを使用して2つのINSERT SQLステートメントを実行し、2つのブログ投稿をpostsに追加できます。 ] テーブル。 最後に、変更をコミットして接続を閉じます。
ファイルを保存して閉じ、pythonコマンドを使用してターミナルで実行します。
python init_db.py
ファイルの実行が完了すると、database.dbという新しいファイルがflask_blogディレクトリに表示されます。 これは、データベースが正常にセットアップされたことを意味します。
次のステップでは、データベースに挿入した投稿を取得して、アプリケーションのホームページに表示します。
ステップ5—すべての投稿を表示する
データベースを設定したので、index()ビュー機能を変更して、データベースにあるすべての投稿を表示できます。
app.pyファイルを開いて、次の変更を行います。
nano app.py
最初の変更では、ファイルの先頭にあるsqlite3モジュールをインポートします。
フラスコブログ/app.py
import sqlite3 from flask import Flask, render_template . . .
次に、データベース接続を作成して返す関数を作成します。 インポートの直後に追加します。
フラスコブログ/app.py
. . .
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.py
. . .
@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ループを使用して各投稿をインデックスページに表示できます。
index.htmlファイルを開きます。
nano templates/index.html
次に、次のように変更します。
フラスコ_ブログ/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 %}はJinjaforループです。これは、後で{% endfor %}で閉じる必要があることを除いて、Pythonforループに似ています。構文。 この構文を使用して、return render_template('index.html', posts=posts)行のindex()関数によって渡されたpostsリストの各項目をループします。 このforループ内で、<a>タグ内の<h2>見出しに投稿タイトルを表示します(後でこのタグを使用して、各投稿に個別にリンクします)。
リテラル変数区切り文字(テンプレート:...)を使用してタイトルを表示します。 postは辞書のようなオブジェクトになるため、post['title']を使用して投稿のタイトルにアクセスできることに注意してください。 同じ方法で投稿の作成日も表示します。
ファイルの編集が完了したら、ファイルを保存して閉じます。 次に、ブラウザのインデックスページに移動します。 ページにデータベースに追加した2つの投稿が表示されます。
index()表示機能を変更して、データベース内のすべての投稿をアプリケーションのホームページに表示するようにしたので、次に、各投稿を1つのページに表示し、ユーザーがそれぞれにリンクできるようにします。個々の投稿。
ステップ6—単一の投稿を表示する
このステップでは、表示機能と新しいHTMLテンプレートを使用して新しいFlaskルートを作成し、IDで個々のブログ投稿を表示します。
このステップが終了すると、URL http://127.0.0.1:5000/1は最初の投稿を表示するページになります(IDが1であるため)。 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()関数をインポートする必要があります。ファイル:
フラスコブログ/app.py
import sqlite3 from flask import Flask, render_template from werkzeug.exceptions import abort . . .
次に、前の手順で作成したget_db_connection()関数の直後にget_post()関数を追加します。
フラスコブログ/app.py
. . .
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()関数を使用して、[X170Xで応答します。 ]エラーコードと関数は実行を終了します。 ただし、投稿が見つかった場合は、post変数の値を返します。
次に、app.pyファイルの最後に次のビュー関数を追加します。
フラスコブログ/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()ビュー関数のpost_idキーワード引数に渡します。 次に、get_post()関数を使用して、指定されたIDに関連付けられたブログ投稿を取得し、結果をpost変数に格納します。この変数は、post.htmlテンプレートに渡します。すぐに作成します。
app.pyファイルを保存し、編集用に新しいpost.htmlテンプレートファイルを開きます。
nano templates/post.html
この新しいpost.htmlファイルに次のコードを入力します。 これはindex.htmlファイルに似ていますが、投稿の内容も表示するだけでなく、単一の投稿のみを表示する点が異なります。
フラスコ_ブログ/templates/post.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 %}
base.htmlテンプレートで定義したtitleブロックを追加して、ページのタイトルに<h2>見出しに同時に表示される投稿タイトルを反映させます。
ファイルを保存して閉じます。
これで、次のURLに移動して、データベースにある2つの投稿と、要求されたブログ投稿が見つからなかったことをユーザーに通知するページを表示できます(ID番号が [の投稿がないため) X221X]これまでのところ):
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ループが次のようになるようにします。
フラスコ_ブログ/templates/index.html
{% 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']を指定します。 url_for()関数は、IDに基づいて各投稿の適切なURLを返します。
ファイルを保存して閉じます。
インデックスページのリンクが期待どおりに機能するようになります。 これで、データベースにブログ投稿を表示するアプリケーションの一部の構築が完了しました。 次に、ブログ投稿を作成、編集、および削除する機能をアプリケーションに追加します。
ステップ7—投稿の変更
これで、データベースに存在するブログ投稿をWebアプリケーションに表示し終えたので、アプリケーションのユーザーが新しいブログ投稿を作成してデータベースに追加し、既存のブログ投稿を編集し、不要なものを削除できるようにする必要があります。ブログ投稿。
新しい投稿を作成する
これまでのところ、データベース内の投稿を表示するアプリケーションがありますが、SQLiteデータベースに直接接続して手動で追加しない限り、新しい投稿を追加する方法はありません。 このセクションでは、タイトルとコンテンツを指定して投稿を作成できるページを作成します。
app.pyファイルを開いて編集します。
nano app.py
まず、Flaskフレームワークから以下をインポートします。
- HTMLフォームを介して送信される着信リクエストデータにアクセスするためのグローバルrequestオブジェクト。
- url_for()関数を使用してURLを生成します。
- flash()関数は、リクエストの処理時にメッセージをフラッシュします。
- redirect()関数を使用して、クライアントを別の場所にリダイレクトします。
次のように、インポートをファイルに追加します。
フラスコブログ/app.py
import sqlite3 from flask import Flask, render_template, request, url_for, flash, redirect from werkzeug.exceptions import abort . . .
flash()機能は、フラッシュされたメッセージをクライアントのブラウザセッションに保存します。これには、秘密鍵を設定する必要があります。 この秘密鍵はセッションを保護するために使用されます。これにより、Flaskは、新しい投稿ページからインデックスページへの移動など、あるリクエストから別のリクエストへの情報を記憶できます。 ユーザーはセッションに保存されている情報にアクセスできますが、秘密鍵を持っていない限り変更することはできません。そのため、誰にも秘密鍵へのアクセスを許可してはなりません。 詳細については、セッションのFlaskドキュメントを参照してください。
秘密鍵を設定するには、app.configオブジェクトを介してSECRET_KEY構成をアプリケーションに追加します。 index()ビュー機能を定義する前に、app定義の直後に追加します。
フラスコブログ/app.py
. . .
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.py
. . .
@app.route('/create', methods=('GET', 'POST'))
def create():
return render_template('create.html')
これにより、GETリクエストとPOSTリクエストの両方を受け入れる/createルートが作成されます。 GETリクエストはデフォルトで受け入れられます。 フォームの送信時にブラウザから送信されるPOSTリクエストも受け入れるには、受け入れられたタイプのリクエストを含むtupleを@app.route()のmethods引数に渡します。 ]デコレータ。
ファイルを保存して閉じます。
テンプレートを作成するには、templatesフォルダー内にcreate.htmlというファイルを開きます。
nano templates/create.html
この新しいファイル内に次のコードを追加します。
フラスコ_ブログ/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()ビュー関数内で行います。 request.methodの値を確認することで、POSTリクエストを個別に処理できます。 その値が'POST'に設定されている場合、それはリクエストがPOSTリクエストであることを意味します。次に、送信されたデータの抽出、検証、データベースへの挿入に進みます。
app.pyファイルを開いて編集します。
nano app.py
create()ビュー関数を変更して、次のように正確に表示します。
フラスコブログ/app.py
. . .
@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ステートメントでは、比較request.method == 'POST'を介して、リクエストがPOSTリクエストである場合にのみ、それに続くコードが実行されるようにします。
次に、送信されたタイトルとコンテンツをrequest.formオブジェクトから抽出します。これにより、リクエスト内のフォームデータにアクセスできます。 タイトルが指定されていない場合、条件if not titleが満たされ、タイトルが必要であることを通知するメッセージがユーザーに表示されます。 一方、タイトルが提供されている場合は、get_db_connection()関数との接続を開き、受け取ったタイトルとコンテンツをpostsテーブルに挿入します。
次に、データベースへの変更をコミットし、接続を閉じます。 ブログ投稿をデータベースに追加した後、redirect()関数を使用してクライアントをインデックスページにリダイレクトし、url_for()関数によって生成されたURLを値'index'として渡します。引数。
ファイルを保存して閉じます。
次に、Webブラウザを使用して/createルートに移動します。
http://127.0.0.1:5000/create
選択したタイトルといくつかのコンテンツをフォームに入力します。 フォームを送信すると、インデックスページに新しい投稿が表示されます。
最後に、点滅するメッセージを表示し、base.htmlテンプレートのナビゲーションバーへのリンクを追加して、この新しいページに簡単にアクセスできるようにします。 テンプレートファイルを開きます。
nano templates/base.html
<nav>タグ内のAboutリンクの後に新しい<li>タグを追加して、ファイルを編集します。 次に、contentブロックのすぐ上に新しいforループを追加して、ナビゲーションバーの下に点滅するメッセージを表示します。 これらのメッセージは、Flaskが提供する特別なget_flashed_messages()機能で利用できます。
フラスコ_ブログ/templates/base.html
<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>
ファイルを保存して閉じます。 ナビゲーションバーには、/createルートにリンクするNew Postアイテムが含まれるようになります。
投稿の編集
ブログを最新の状態にするには、既存の投稿を編集できる必要があります。 このセクションでは、投稿を編集するプロセスを簡素化するために、アプリケーションで新しいページを作成する方法について説明します。
まず、app.pyファイルに新しいルートを追加します。 その表示機能は、編集が必要な投稿のIDを受け取ります。URLは/post_id/editの形式になり、post_id変数は投稿のIDになります。 app.pyファイルを開いて編集します。
nano app.py
次に、ファイルの最後に次のedit()表示機能を追加します。 既存の投稿の編集は新しい投稿の作成に似ているため、この表示機能はcreate()表示機能に似ています。
フラスコブログ/app.py
. . .
@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引数を介してID番号をedit()関数に渡します。 この値をget_post()関数に追加して、提供されたIDに関連付けられた投稿をデータベースからフェッチします。 新しいデータは、if request.method == 'POST'条件内で処理されるPOSTリクエストで送信されます。
新しい投稿を作成するときと同じように、最初にrequest.formオブジェクトからデータを抽出し、タイトルに空の値がある場合はメッセージをフラッシュします。それ以外の場合は、データベース接続を開きます。 次に、データベース内の投稿のIDがURL内のIDと等しい新しいタイトルと新しいコンテンツを設定して、postsテーブルを更新します。
GETリクエストの場合、get_post()関数の戻り値を保持するpost変数を渡すedit.htmlテンプレートをレンダリングします。 これを使用して、編集ページに既存のタイトルとコンテンツを表示します。
ファイルを保存して閉じてから、新しいedit.htmlテンプレートを作成します。
nano templates/edit.html
この新しいファイル内に次のコードを記述します。
フラスコ_ブログ/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
次のようにファイルを編集します。
フラスコ_ブログ/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を使用して各投稿の編集ページにリンクします。 ] リンク。
投稿の削除
投稿を公開する必要がなくなる場合があります。そのため、投稿を削除する機能が重要になります。 このステップでは、アプリケーションに削除機能を追加します。
まず、edit()ビュー機能と同様に、POSTリクエストを受け入れる新しい/ID/deleteルートを追加します。 新しいdelete()表示機能は、URLから削除される投稿のIDを受け取ります。 app.pyファイルを開きます。
nano app.py
ファイルの下部に次のビュー関数を追加します。
フラスコブログ/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 FROMSQLコマンドを実行して投稿を削除します。 データベースへの変更をコミットし、メッセージをフラッシュしながら接続を閉じて、投稿が正常に削除されたことをユーザーに通知し、インデックスページにリダイレクトします。
テンプレートファイルはレンダリングしないことに注意してください。これは、編集ページにDeleteボタンを追加するだけだからです。
edit.htmlテンプレートファイルを開きます。
nano templates/edit.html
次に、<hr>タグの後、{% endblock %}行の直前に次の<form>タグを追加します。
フラスコ_ブログ/templates/edit.html
<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アプリケーションで電子メールメッセージを送信するタスクを支援します。