FlaskアプリケーションでSQLiteデータベースを使用する方法
序章
Webアプリケーションでは、通常、データの整理されたコレクションであるデータベースが必要です。 データベースを使用して、効率的に取得および操作できる永続データを保存および維持します。 たとえば、ソーシャルメディアアプリケーションでは、ユーザーデータ(個人情報、投稿、コメント、フォロワー)が効率的に操作できる方法で保存されているデータベースがあります。 さまざまな要件や条件に応じて、データベースにデータを追加、取得、変更、または削除できます。 Webアプリケーションでは、これらの要件は、ユーザーが新しい投稿を追加したり、投稿を削除したり、アカウントを削除したりする場合があります。これにより、投稿が削除される場合と削除されない場合があります。 データを操作するために実行するアクションは、アプリケーションの特定の機能によって異なります。 たとえば、タイトルのない投稿をユーザーに追加させたくない場合があります。
Flask は、Python言語でWebアプリケーションを作成するための便利なツールと機能を提供する軽量のPythonWebフレームワークです。 SQLite は、シンプルで高速なオープンソースの SQLエンジンであり、Pythonで使用してアプリケーションデータを保存および操作できます。 SQLiteはPythonでうまく機能します。これは、Python標準ライブラリが sqlite3モジュールを提供し、何もインストールせずにSQLiteデータベースと対話するために使用できるためです。 PythonでSQLiteを使用すると、他のデータベースエンジンと比較して最小限のセットアップも必要になります。
このチュートリアルでは、FlaskでSQLiteを使用して、CRUD(作成、読み取り、更新、削除)をカバーする基本的なデータ操作を実行する方法を示す小さなWebアプリケーションを構築します。 Webアプリケーションは、インデックスページに投稿を表示する基本的なブログになります。 ユーザーは、個々の投稿を作成、編集、および削除できます。
前提条件
-
ローカルのPython3プログラミング環境については、 Python3シリーズのローカルプログラミング環境をインストールしてセットアップする方法のチュートリアルに従ってください。 このチュートリアルでは、プロジェクトディレクトリを呼び出します
flask_app
. -
ルート、ビュー関数、テンプレートなどの基本的なFlaskの概念の理解。 Flaskに慣れていない場合は、FlaskとPythonを使用して最初のWebアプリケーションを作成する方法およびFlaskアプリケーションでテンプレートを使用する方法を確認してください。
-
基本的なHTMLの概念の理解。 背景知識については、HTMLを使用してWebサイトを構築する方法チュートリアルシリーズを確認できます。
-
SQLiteの使用方法の基本的な理解。 Ubuntu20.04にSQLiteをインストールして使用する方法を参照してください。
ステップ1—データベースのセットアップ
このステップでは、データ(アプリケーションのブログ投稿)を保存するために使用するSQLiteデータベースを設定します。 次に、データベースにいくつかのエントリ例を入力します。
sqlite3 モジュールを使用して、データベースと対話します。データベースは、標準のPythonライブラリですぐに利用できます。
SQLiteのデータはテーブルと列に保存されるため、最初に次のテーブルを作成する必要があります。 posts
必要な列で。 作成します .sql
を作成するためのSQLコマンドを含むファイル posts
いくつかの列を持つテーブル。 次に、このスキーマファイルを使用してデータベースを作成します。
と呼ばれるデータベーススキーマファイルを開きます schema.sql
あなたの中に flask_app
ディレクトリ:
- 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
);
ファイルを保存して閉じます。
このスキーマファイルでは、最初に posts
すでに存在する場合はテーブル。 これにより、という名前の別のテーブルの可能性が回避されます posts
既存の場合、混乱する動作が発生する可能性があります(たとえば、列が異なる場合)。 テーブルをまだ作成していないため、SQLコマンドは実行されないため、ここでは当てはまりません。 これにより、このスキーマファイルを実行するたびに既存のデータがすべて削除されることに注意してください。 この目的のために、このスキーマは1回だけ実行しますが、挿入したデータを削除して空のデータベースから再開するために、もう一度実行することをお勧めします。
次に、 CREATE TABLE posts
を作成するには posts
次の列を持つテーブル:
id
:主キーを表す整数。 このキーには、各エントリ(つまり、各ブログ投稿)のデータベースによって一意の値が割り当てられます。AUTOINCREMENT
投稿IDが自動的にインクリメントされるため、最初の投稿のIDは次のようになります。1
、およびその後に追加された投稿のIDは2
、 等々。 他の投稿が削除された場合でも、各投稿は常に同じIDを持ちます。created
:ブログ投稿が作成された時刻。NOT NULL
この列が空であってはならないことを意味し、DEFAULT
値はCURRENT_TIMESTAMP
値。投稿がデータベースに追加された時刻です。 と同じようにid
、この列の値は自動的に入力されるため、指定する必要はありません。title
:投稿のタイトル。NOT NULL
この列を空にすることはできないことを意味します。content
:投稿内容。NOT NULL
この列を空にすることはできないことを意味します。
今、あなたは使用します schema.sql
データベースを作成するファイル。 そのためには、SQLiteを生成するPythonファイルを作成します .db
これに基づくデータベースファイル schema.sql
ファイル。 名前の付いたファイルを開きます init_db.py
あなたの中に flask_app
ディレクトリ:
- 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_app
ディレクトリ。 これは、データベースが正常にセットアップされたことを意味します。
次に、小さなFlaskアプリケーションを作成し、データベースに挿入した2つの投稿を取得して、インデックスページに表示します。
ステップ2—投稿を表示する
このステップでは、データベースにあるブログ投稿が表示されるインデックスページを使用してFlaskアプリケーションを作成します。
プログラミング環境をアクティブにしてFlaskをインストールした状態で、次のファイルを開きます。 app.py
あなたの中で編集するため flask_app
ディレクトリ:
- nano app.py
このファイルはデータベース接続をセットアップし、その接続を使用する単一のFlaskルートを作成します。 次のコードをファイルに追加します。
import sqlite3
from flask import Flask, render_template
app = Flask(__name__)
def get_db_connection():
conn = sqlite3.connect('database.db')
conn.row_factory = sqlite3.Row
return conn
@app.route('/')
def index():
conn = get_db_connection()
posts = conn.execute('SELECT * FROM posts').fetchall()
conn.close()
return render_template('index.html', posts=posts)
ファイルを保存して閉じます。
上記のコードでは、最初に sqlite3
データベースに接続するために使用するモジュール。 次に、インポートします Flask
クラスと render_template()
からの機能 flask
パッケージ。 と呼ばれるFlaskアプリケーションインスタンスを作成します app
. と呼ばれる関数を定義します get_db_connection()
、への接続を開きます database.db
以前に作成したデータベースファイルで、row_factory属性をに設定します sqlite3.Row
そのため、名前に基づいて列にアクセスできます。 これは、データベース接続が通常のPythonディクショナリのように動作する行を返すことを意味します。 最後に、関数は conn
データベースへのアクセスに使用する接続オブジェクト。
次に、 app.route()
Flaskビュー関数を作成するためのデコレータ index()
. あなたは get_db_connection()
データベース接続を開く関数。 次に、SQLクエリを実行して、postsテーブルからすべてのエントリを選択します。 fetchall()メソッドを使用して、クエリ結果のすべての行をフェッチします。これにより、前の手順でデータベースに挿入した投稿のリストが返されます。
を使用してデータベース接続を閉じます close()
メソッドとレンダリングの結果を返します index.html
テンプレート。 あなたも合格します posts
データベースから取得した結果を含む引数としてのオブジェクト。 これにより、次のブログ投稿にアクセスできるようになります。 index.html
テンプレート。
データベースにある投稿をインデックスページに表示するには、最初にベーステンプレートを作成します。このテンプレートには、コードの繰り返しを避けるために他のテンプレートでも使用されるすべての基本的なHTMLコードが含まれます。 次に、を作成します index.html
レンダリングしたテンプレートファイル index()
関数。 テンプレートの詳細については、Flaskアプリケーションでテンプレートを使用する方法を参照してください。
テンプレートディレクトリを作成し、という名前の新しいテンプレートを開きます base.html
:
- mkdir templates
- nano templates/base.html
内に次のコードを追加します base.html
ファイル:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %} {% endblock %}- FlaskApp</title>
<style>
.post {
padding: 10px;
margin: 5px;
background-color: #f3f3f3
}
nav a {
color: #d64161;
font-size: 3em;
margin-left: 50px;
text-decoration: none;
}
</style>
</head>
<body>
<nav>
<a href="{{ url_for('index') }}">FlaskApp</a>
<a href="#">About</a>
</nav>
<hr>
<div class="content">
{% block content %} {% endblock %}
</div>
</body>
</html>
ファイルを保存して閉じます。
この基本テンプレートには、他のテンプレートで再利用する必要があるすべてのHTMLボイラープレートが含まれています。 The title
各ページのタイトルを設定するためにブロックが置き換えられ、 content
ブロックは各ページのコンテンツに置き換えられます。 ナビゲーションバーには2つのリンクがあります。1つは、を使用するインデックスページ用です。 url_for()
リンクするヘルパー関数 index()
表示機能、およびアプリケーションに1つを含めることを選択した場合は、[バージョン情報]ページ用のもう1つ。
次に、というテンプレートを開きます index.html
. これは、で参照したテンプレートです。 app.py
ファイル:
- nano templates/index.html
次のコードを追加します。
{% extends 'base.html' %}
{% block content %}
<h1>{% block title %} Posts {% endblock %}</h1>
{% for post in posts %}
<div class='post'>
<p>{{ post['created'] }}</p>
<h2>{{ post['title'] }}</h2>
<p>{{ post['content'] }}</p>
</div>
{% endfor %}
{% endblock %}
ファイルを保存して閉じます。
上記のコードでは、 base.html
テンプレートを作成し、その内容を置き換えます content
ブロック。 あなたは <h1>
タイトルを兼ねる見出し。
行でJinjaforloopを使用します {% for post in posts %}
の各投稿を確認するには posts
リスト。 作成日にアクセスするには、 {{ post['created'] }}
、タイトル経由 {{ post['title'] }}
、および経由での投稿コンテンツ {{ post['content'] }}
.
あなたの中に flask_app
仮想環境がアクティブ化されているディレクトリ、アプリケーションについてFlaskに通知します(app.py
この場合)を使用して FLASK_APP
環境変数:
- export FLASK_APP=app
次に、 FLASK_ENV
環境変数から development
アプリケーションを開発モードで実行し、デバッガーにアクセスします。 Flaskデバッガーの詳細については、Flaskアプリケーションでエラーを処理する方法を参照してください。 これを行うには、次のコマンドを使用します(Windowsでは、 set
それ以外の export
):
- export FLASK_ENV=development
次に、アプリケーションを実行します。
- flask run
開発サーバーが実行されている状態で、ブラウザーを使用して次のURLにアクセスします。
http://127.0.0.1:5000/
最初の開始時にデータベースに追加した投稿が表示されます。
データベースの投稿をインデックスページに表示しました。 ここで、ユーザーが新しい投稿を追加できるようにする必要があります。 次のステップで、投稿を追加するための新しいルートを追加します。
ステップ3—投稿を作成する
このステップでは、Flaskアプリケーションに新しいルートを追加します。これにより、ユーザーは新しいブログ投稿をデータベースに追加でき、インデックスページに表示されます。
ユーザーが投稿のタイトルと投稿のコンテンツを入力するWebフォームを含むページを追加します。 このフォームは、ユーザーが空のフォームを送信しないように検証されます。 フォームが無効であることをユーザーに通知するには、フラッシュメッセージを使用します。このメッセージは1回だけ表示され、次のリクエストで消えます(たとえば、別のページに移動した場合)。
開発サーバーを実行したままにして、新しいターミナルウィンドウを開きます。
まず、 app.py
ファイル:
- nano app.py
Webフォームを処理するには、からいくつかのものをインポートする必要があります。 flask
パッケージ:
- 送信されたデータにアクセスするためのグローバルrequestオブジェクト。
- url_for()関数を使用してURLを生成します。
- flash()関数は、リクエストが無効な場合にメッセージをフラッシュします。
- redirect()関数は、データベースに投稿を追加した後、ユーザーをインデックスページにリダイレクトします。
これらのインポートをファイルの最初の行に追加します。
from flask import Flask, render_template, request, url_for, flash, redirect
# ...
The flash()
関数は、フラッシュされたメッセージをクライアントのブラウザセッションに保存します。これには、秘密鍵を設定して、ある要求から別の要求への情報を記憶するセッションを保護する必要があります。 誰にもあなたの秘密鍵へのアクセスを許可してはなりません。 詳細については、セッションのFlaskドキュメントを参照してください。
秘密鍵を追加して設定します SECRET_KEY
を介したアプリケーションへの構成 app.config
物体。 の横に追加します app
インスタンス定義。
# ...
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your secret key'
秘密鍵は長いランダムな文字列である必要があることに注意してください。 Webフォームと秘密鍵の構成の詳細については、FlaskアプリケーションでWebフォームを使用する方法を参照してください。
次に、最後に次のルートを追加します app.py
ファイル:
# ...
@app.route('/create/', methods=('GET', 'POST'))
def create():
return render_template('create.html')
ファイルを保存して閉じます。
このルートでは、タプルを渡します ('GET', 'POST')
に methods
GET要求とPOST要求の両方を許可するパラメーター。 GETリクエストは、サーバーからデータを取得するために使用されます。 POSTリクエストは、特定のルートにデータを投稿するために使用されます。 デフォルトでは、GETリクエストのみが許可されます。 ユーザーが最初にリクエストしたとき /create
GETリクエストを使用してルーティングします。 create.html
レンダリングされます。 後でこのルートを編集して、ユーザーが新しい投稿を作成するためのWebフォームに入力して送信するときのPOSTリクエストを処理します。
新しいを開く create.html
テンプレート:
- nano templates/create.html
次のコードを追加します。
{% extends 'base.html' %}
{% block content %}
<h1>{% block title %} Add a New Post {% endblock %}</h1>
<form method="post">
<label for="title">Title</label>
<br>
<input type="text" name="title"
placeholder="Post title"
value="{{ request.form['title'] }}"></input>
<br>
<label for="content">Post Content</label>
<br>
<textarea name="content"
placeholder="Post content"
rows="15"
cols="60"
>{{ request.form['content'] }}</textarea>
<br>
<button type="submit">Submit</button>
</form>
{% endblock %}
ファイルを保存して閉じます。
基本テンプレートを拡張し、見出しをタイトルとして設定し、 <form>
属性を持つタグ method
に設定 post
フォームがPOSTリクエストを送信することを示します。 名前の付いたテキストフィールドがあります title
、のタイトルデータにアクセスするために使用します /create
ルート。 テキストフィールドの値を次のように設定します request.form['title']
これは空であるか、フォームが無効な場合はタイトルの保存バージョンであるため、問題が発生したときにタイトルが失われることはありません。
タイトル入力フィールドの後に、という名前のテキスト領域を追加します content
値で {{ request.form['content'] }}
フォームが無効な場合に投稿コンテンツを復元します。
最後に、フォームの最後に[送信]ボタンがあります。
これで、開発サーバーが実行されている状態で、ブラウザーを使用してに移動します。 /create
ルート:
http://127.0.0.1:5000/create
新しい投稿の追加ページが表示され、投稿タイトルの入力フィールド、投稿のコンテンツのテキスト領域、および送信ボタンが表示されます。
フォームに入力して送信し、サーバーにPOSTリクエストを送信すると、POSTリクエストを処理しなかったため、何も起こりません。 /create
ルート。
開ける app.py
ユーザーが送信するPOSTリクエストを処理するには:
- 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!')
elif not content:
flash('Content 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')
ファイルを保存して閉じます。
POSTリクエストは内部で処理します if request.method == 'POST'
調子。 ユーザーが送信したタイトルとコンテンツを request.form
物体。 タイトルが空の場合は、 flash()
メッセージをフラッシュする機能 Title is required!
. 空のコンテンツの場合も同じようにします。
タイトルとコンテンツの両方が提供されている場合は、を使用してデータベース接続を開きます。 get_db_connection()
関数。 あなたは execute()
実行するメソッド INSERT INTO
新しい投稿をに追加するSQLステートメント posts
ユーザーが値として送信するタイトルとコンテンツを含むテーブル。 あなたは ?
データをテーブルに安全に挿入するためのプレースホルダー。 トランザクションをコミットして、接続を閉じます。 最後に、ユーザーをインデックスページにリダイレクトします。このページでは、既存の投稿の下に新しい投稿が表示されます。
警告:Python文字列操作を使用してSQLステートメント文字列を動的に作成しないでください。 常に使用してください ?
値を動的に置き換えるためのSQLステートメントのプレースホルダー。 値のタプルを2番目の引数として execute()
値をSQLステートメントにバインドするメソッド。 これにより、SQLインジェクション攻撃が防止されます。
開発サーバーが実行されている状態で、ブラウザを使用してに移動します /create
ルート:
http://127.0.0.1:5000/create
フォームに記入して送信します。
新しい投稿が表示されるインデックスページにリダイレクトされます。
タイトルのないフォームまたはコンテンツのないフォームを送信すると、投稿はデータベースに追加されず、インデックスページにリダイレクトされず、その理由に関するフィードバックを受け取ることもありません。 これは、フラッシュされたメッセージがまだどこにも表示されないように設定していないためです。
開ける base.html
ナビゲーションバーの[作成]ページへのリンクを追加し、その下に点滅するメッセージを表示します。
- nano templates/base.html
次のようにファイルを編集します。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %} {% endblock %} - FlaskApp</title>
<style>
.post {
padding: 10px;
margin: 5px;
background-color: #f3f3f3
}
nav a {
color: #d64161;
font-size: 3em;
margin-left: 50px;
text-decoration: none;
}
.alert {
padding: 20px;
margin: 5px;
color: #970020;
background-color: #ffd5de;
}
</style>
</head>
<body>
<nav>
<a href="{{ url_for('index') }}">FlaskApp</a>
<a href="{{ url_for('create') }}">Create</a>
<a href="#">About</a>
</nav>
<hr>
<div class="content">
{% for message in get_flashed_messages() %}
<div class="alert">{{ message }}</div>
{% endfor %}
{% block content %} {% endblock %}
</div>
</body>
</html>
ファイルを保存して閉じます。
ここで、新しいを追加します <a>
[作成]ページを指すナビゲーションバーへのリンク。
ジンジャを使う for
フラッシュされたメッセージを通過するためにループします。 これらはで利用可能です get_flashed_messages()
特殊機能。 各メッセージはに表示されます <div>
と呼ばれるCSSクラスのタグ alert
. あなたはこれをスタイリングします <div>
内のタグ <style>
のタグ <head>
セクション。
インデックスページを更新すると、ナビゲーションバーに新しいリンクが表示されます。
作成リンクをクリックして、空のフォームを送信します。 「タイトルが必要です!」というメッセージが点滅します。
タイトルフィールドに入力し、コンテンツテキスト領域を空のままにします。 もう一度フォームを送信すると、「コンテンツが必要です!」というメッセージが表示されます。 メッセージ。 「タイトルが必要です!」に注目してください。 メッセージが消えました。 これは、フラッシュメッセージであり、永続的なメッセージではないためです。
これで、新しい投稿を追加する方法があります。 次に、ユーザーが既存の投稿を編集できるようにするための新しいルートを追加します。
ステップ4—投稿を編集する
このステップでは、ユーザーが既存の投稿を編集できるように、アプリケーションに新しいルートを追加します。
まず、コードの繰り返しを回避し、コードを分離して保守を容易にするために、IDを取得し、それに関連付けられた投稿をデータベースから取得する新しい関数を追加します。 この関数を使用して、編集する投稿データを取得し、次のステップで削除する場合の投稿を取得します。
開ける app.py
:
- nano app.py
投稿を取得するために使用する関数は、 404 Not Found
リクエストされた投稿のIDが既存の投稿のいずれとも一致しない場合はエラーになります。 これを行うには、 abort()関数を使用します。この関数は、要求を中止し、エラーメッセージで応答します。 詳細については、Flaskアプリケーションでエラーを処理する方法を参照してください。
追加します abort()
インポートへの機能:
from flask import Flask, render_template, request, url_for, flash, redirect, 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.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!')
elif not content:
flash('Content 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)
ファイルを保存して閉じます。
ルートを使用します /<int:id>/edit/
、 と int:
正の整数を受け入れるコンバーターであること。 と id
編集する投稿を決定するURL変数です。 例えば、 /2/edit/
次のIDで投稿を編集できます 2
. IDはURLからに渡されます edit()
ビュー機能。 の値を渡します id
への議論 get_post()
指定されたIDに関連付けられた投稿をデータベースからフェッチする関数。 これは次のように応答することを忘れないでください 404 Not Found
指定されたIDの投稿が存在しない場合はエラーになります。
最後の行は、というテンプレートファイルをレンダリングします edit.html
、およびパス post
投稿データを持つ変数。 これを使用して、編集ページに既存のタイトルとコンテンツを表示します。
The if request.method == 'POST'
ブロックは、ユーザーが送信する新しいデータを処理します。 新しい投稿を追加するのと同様に、タイトルとコンテンツを抽出します。 タイトルまたはコンテンツが提供されていない場合は、メッセージをフラッシュします。
フォームが有効な場合は、データベース接続を開き、 UPDATE
を更新するSQLステートメント posts
新しいタイトルと新しいコンテンツを設定してテーブルを作成します。データベース内の投稿のIDは、URLに含まれていたIDと同じです。 トランザクションをコミットし、接続を閉じて、インデックスページにリダイレクトします。
次に、ユーザーが編集できるページを作成する必要があります。 新しいを開く edit.html
テンプレート:
- nano templates/edit.html
次のコードを追加します。
{% extends 'base.html' %}
{% block content %}
<h1>{% block title %} Edit "{{ post['title'] }}" {% endblock %}</h1>
<form method="post">
<label for="title">Title</label>
<br>
<input type="text" name="title"
placeholder="Post title"
value="{{ request.form['title'] or post['title'] }}"></input>
<br>
<label for="content">Post Content</label>
<br>
<textarea name="content"
placeholder="Post content"
rows="15"
cols="60"
>{{ request.form['content'] or post['content'] }}</textarea>
<br>
<button type="submit">Submit</button>
</form>
{% endblock %}
ファイルを保存して閉じます。
これは、のコードに似ています create.html
テンプレート。ただし、行のページのタイトル内に投稿のタイトルを表示する場合を除きます。 {% block title %} Edit "{{ post['title'] }}" {% 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 %} Posts {% endblock %}</h1>
{% for post in posts %}
<div class='post'>
<p>{{ post['created'] }}</p>
<h2>{{ post['title'] }}</h2>
<p>{{ post['content'] }}</p>
<a href="{{ url_for('edit', id=post['id']) }}">Edit</a>
</div>
{% endfor %}
{% endblock %}
ファイルを保存して閉じます。
追加しました <a>
にリンクするタグ edit()
ビュー機能。 あなたはあなたが持っている投稿IDを渡します post['id'])
に url_for()
投稿の編集リンクを生成する関数。 これにより、その下にある各投稿の編集ページへのリンクが追加されます。
インデックスページを更新し、編集リンクをクリックして投稿を編集します。
これで、新しい投稿を追加したり、既存の投稿を編集したりできます。 次に、ユーザーが既存の投稿を削除できるようにするボタンを追加します。
ステップ5—投稿を削除する
このステップでは、ユーザーが投稿を削除できるように、[編集]ページに[削除]ボタンを追加します。
まず、新しいものを追加します /id/delete
POSTリクエストを受け入れるルート。 edit()
ビュー機能。 あなたの新しい delete()
ビュー機能は、URLから削除される投稿のIDを受け取り、を使用してそれを取得します get_post()
関数を作成し、存在する場合はデータベースから削除します。
を開きます 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リクエストのみを受け入れます。 methods
パラメータ。 これは、 /ID/delete
ブラウザのルートは 405 Method Not Allowed
エラー。WebブラウザはデフォルトでGETリクエストを使用しているためです。 投稿を削除するには、ユーザーはこのルートにPOSTリクエストを送信するボタンをクリックします。
この関数は、削除する投稿のIDを受け取ります。 このIDを使用して、 get_post()
関数。 これは、 404 Not Found
指定されたIDの投稿が存在しない場合はエラーになります。 データベース接続を開き、 DELETE FROM
投稿を削除するSQLコマンド。 あなたが使う WHERE id = ?
削除する投稿を指定します。
データベースへの変更をコミットし、接続を閉じます。 メッセージをフラッシュして、投稿が正常に削除されたことをユーザーに通知し、インデックスページにリダイレクトします。
テンプレートファイルはレンダリングしないことに注意してください。 これは、[編集]ページに[削除]ボタンを追加するだけだからです。
を開きます edit.html
テンプレートファイル:
- nano templates/edit.html
次に、以下を追加します <hr>
と <form>
直前のタグ {% endblock %}
ライン:
<button type="submit">Submit</button>
</form>
<hr>
<form action="{{ url_for('delete', id=post['id']) }}" method="POST">
<input type="submit" value="Delete Post"
onclick="return confirm('Are you sure you want to delete this post?')">
</form>
{% endblock %}
ファイルを保存して閉じます。
ここに、POSTリクエストを送信するWebフォームがあります。 delete()
ビュー機能。 あなたは合格します post['id']
削除する投稿を指定します。 Webブラウザーで使用可能なconfirm()メソッドを使用して、要求を送信する前に確認メッセージを表示します。
次に、投稿の[編集]ページに再度移動して、削除してみます。
http://127.0.0.1:5000/1/edit
削除を確認すると、インデックスページにリダイレクトされ、投稿は表示されなくなります。 ナビゲーションバーの下に、投稿が正常に削除されたことを通知するフラッシュメッセージが表示されます。
これで、Flaskアプリケーションのデータベースから不要な投稿を削除する方法があります。
結論
SQLiteデータベースと通信する小さなWebブログを作成しました。 Flaskアプリケーションには、データベースへの新しいデータの追加、データの取得とページへの表示、既存のデータの編集と削除などの基本的な機能があります。
PythonとFlaskでSQLiteを使用する方法の詳細については、次のチュートリアルを参照してください。
- Python3でsqlite3モジュールを使用する方法
- FlaskおよびSQLiteで1対多のデータベース関係を使用する方法
- FlaskおよびSQLiteとの1対多のデータベース関係でアイテムを変更する方法
- FlaskおよびSQLiteで多対多のデータベース関係を使用する方法
Flaskの詳細については、Flaskシリーズの他のチュートリアルをご覧ください。