FlaskおよびSQLiteで1対多のデータベース関係を使用する方法

提供:Dev Guides
移動先:案内検索

著者はCOVID-19救済基金を選択し、 Write forDOnationsプログラムの一環として寄付を受け取りました。

序章

Flask は、Python言語を使用してWebアプリケーションを構築するためのフレームワークであり、 SQLite は、Pythonでアプリケーションデータを格納するために使用できるデータベースエンジンです。 このチュートリアルでは、FlaskとSQLiteを使用して、ユーザーがToDoアイテムのリストを作成できるToDoアプリケーションを作成します。 FlaskでSQLiteを使用する方法と、1対多のデータベース関係がどのように機能するかを学習します。

1対多のデータベース関係は、あるテーブルのレコードが別のテーブルの複数のレコードを参照できる2つのデータベーステーブル間の関係です。 たとえば、ブログアプリケーションでは、投稿を保存するためのテーブルは、コメントを保存するためのテーブルと1対多の関係を持つことができます。 各投稿は多くのコメントを参照でき、各コメントは1つの投稿を参照します。 したがって、 1つの投稿は、多くのコメントと関係があります。 postテーブルは親テーブルであり、commentsテーブルは子テーブルです。親テーブルのレコードは、子テーブルの多くのレコードを参照できます。 これは、各テーブルの関連データにアクセスできるようにするために重要です。

SQLiteは移植性があり、Pythonで動作するために追加の設定を必要としないため、SQLiteを使用します。 また、MySQLやPostgresなどのより大きなデータベースに移動する前にアプリケーションのプロトタイプを作成する場合にも最適です。 適切なデータベースシステムを選択する方法の詳細については、 SQLiteとMySQLとPostgreSQL:リレーショナルデータベース管理システムの比較の記事を参照してください。

前提条件

このガイドに従う前に、次のものが必要です。

  • ローカルPython3プログラミング環境については、ローカルマシン用のPython3シリーズのローカルプログラミング環境をインストールおよびセットアップする方法のチュートリアルに従ってください。 このチュートリアルでは、プロジェクトディレクトリをflask_todoと呼びます。
  • ルートの作成、HTMLテンプレートのレンダリング、SQLiteデータベースへの接続などの基本的なFlaskの概念の理解。 これらの概念に精通していない場合は、 Python 3でFlaskを使用してWebアプリケーションを作成する方法に従うことができますが、必須ではありません。

ステップ1—データベースの作成

このステップでは、プログラミング環境をアクティブ化し、Flaskをインストールし、SQLiteデータベースを作成して、サンプルデータを入力します。 外部キーを使用して、リストとアイテムの間に1対多の関係を作成する方法を学習します。 外部キーは、データベーステーブルを別のテーブルに関連付けるために使用されるキーであり、子テーブルとその親テーブルの間のリンクです。

プログラミング環境をまだアクティブ化していない場合は、プロジェクトディレクトリ(flask_todo)にいることを確認し、次のコマンドを使用してアクティブ化します。

source env/bin/activate

プログラミング環境がアクティブ化されたら、次のコマンドを使用してFlaskをインストールします。

pip install flask

インストールが完了すると、ToDoデータを格納するために必要なテーブルを作成するためのSQLコマンドを含むデータベーススキーマファイルを作成できるようになります。 ToDoリストを格納するためのlistsというテーブルと、各リストの項目を格納するためのitemsテーブルの2つのテーブルが必要になります。

flask_todoディレクトリ内にあるschema.sqlというファイルを開きます。

nano schema.sql

このファイル内に次のSQLコマンドを入力します。

フラスコ_todo/schema.sql

DROP TABLE IF EXISTS lists;
DROP TABLE IF EXISTS items;

CREATE TABLE lists (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    title TEXT NOT NULL
);

CREATE TABLE items (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    list_id INTEGER NOT NULL,
    created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    content TEXT NOT NULL,
    FOREIGN KEY (list_id) REFERENCES lists (id)
);

ファイルを保存して閉じます。

最初の2つのSQLコマンドはDROP TABLE IF EXISTS lists;DROP TABLE IF EXISTS items;です。これらは、listsitemsという名前の既存のテーブルを削除するため、混乱を招く動作は見られません。 これにより、これらのSQLコマンドを使用するたびにデータベースにあるすべてのコンテンツが削除されるため、このチュートリアルを終了して最終結果を試すまで、Webアプリケーションに重要なコンテンツを書き込まないようにしてください。

次に、CREATE TABLE listsを使用して、次の列を持つTo Doリスト(学習リスト、作業リスト、ホームリストなど)を格納するlistsテーブルを作成します。

  • id主キーを表す整数。これには、各エントリのデータベースによって一意の値が割り当てられます(つまり、 やることリスト)。
  • created:やることリストが作成された時刻。 NOT NULLは、この列が空であってはならないことを意味し、DEFAULT値はCURRENT_TIMESTAMP値であり、リストがデータベースに追加された時刻です。 idと同様に、この列の値は自動的に入力されるため、指定する必要はありません。
  • title:リストのタイトル。

次に、itemsというテーブルを作成して、やること項目を保存します。 このテーブルには、ID、アイテムが属するリストを識別するためのlist_id整数列、作成日、およびアイテムのコンテンツがあります。 アイテムをデータベース内のリストにリンクするには、外部キー制約と行FOREIGN KEY (list_id) REFERENCES lists (id)を使用します。 ここで、listsテーブルは親テーブルであり、外部キー制約によって参照されているテーブルです。これは、リストに複数のアイテムを含めることができることを示しています。 itemsテーブルは、子テーブルであり、制約が適用されるテーブルです。 これは、アイテムが単一のリストに属していることを意味します。 list_id列は、lists親テーブルのid列を参照します。

リストには多くのアイテムを含めることができ、アイテムは 1つのリストにのみ属するため、listsテーブルとitemsテーブルの関係は[ X155X]1対多の関係。

次に、schema.sqlファイルを使用してデータベースを作成します。 flask_todoディレクトリ内のinit_db.pyという名前のファイルを開きます。

nano init_db.py

次に、次のコードを追加します。

フラスコ_todo/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 lists (title) VALUES (?)", ('Work',))
cur.execute("INSERT INTO lists (title) VALUES (?)", ('Home',))
cur.execute("INSERT INTO lists (title) VALUES (?)", ('Study',))

cur.execute("INSERT INTO items (list_id, content) VALUES (?, ?)",
            (1, 'Morning meeting')
            )

cur.execute("INSERT INTO items (list_id, content) VALUES (?, ?)",
            (2, 'Buy fruit')
            )

cur.execute("INSERT INTO items (list_id, content) VALUES (?, ?)",
            (2, 'Cook dinner')
            )

cur.execute("INSERT INTO items (list_id, content) VALUES (?, ?)",
            (3, 'Learn Flask')
            )

cur.execute("INSERT INTO items (list_id, content) VALUES (?, ?)",
            (3, 'Learn SQLite')
            )

connection.commit()
connection.close()

ファイルを保存して閉じます。

ここでは、このプログラムを実行すると作成されるdatabase.dbというファイルに接続します。 次に、schema.sqlファイルを開き、複数のSQLステートメントを同時に実行する executescript()メソッドを使用して実行します。

schema.sqlを実行すると、listsテーブルとitemsテーブルが作成されます。 次に、カーソルオブジェクトを使用して、いくつかのINSERT SQLステートメントを実行し、3つのリストと5つのToDo項目を作成します。

list_id列を使用して、リストのid値を介して各アイテムをリストにリンクします。 たとえば、Workリストはデータベースへの最初の挿入であるため、IDは1になります。 これは、Morning meetingタスクアイテムをWorkにリンクする方法です。同じルールが他のリストとアイテムにも適用されます。

最後に、変更をコミットして接続を閉じます。

プログラムを実行します。

python init_db.py

実行後、database.dbという新しいファイルがflask_todoディレクトリに表示されます。

環境をアクティブ化し、Flaskをインストールし、SQLiteデータベースを作成しました。 次に、データベースからリストとアイテムを取得し、アプリケーションのホームページに表示します。

ステップ2—やること項目の表示

このステップでは、前のステップで作成したデータベースを、やることリストと各リストの項目を表示するFlaskアプリケーションに接続します。 SQLite結合を使用して2つのテーブルからデータをクエリする方法と、ToDo項目をリストごとにグループ化する方法を学習します。

まず、アプリケーションファイルを作成します。 flask_todoディレクトリ内のapp.pyという名前のファイルを開きます。

nano app.py

次に、次のコードをファイルに追加します。

フラスコ_todo/app.py

from itertools import groupby
import sqlite3
from flask import Flask, render_template, request, flash, redirect, url_for


def get_db_connection():
    conn = sqlite3.connect('database.db')
    conn.row_factory = sqlite3.Row
    return conn


app = Flask(__name__)
app.config['SECRET_KEY'] = 'this should be a secret random string'


@app.route('/')
def index():
    conn = get_db_connection()
    todos = conn.execute('SELECT i.content, l.title FROM items i JOIN lists l \
                          ON i.list_id = l.id ORDER BY l.title;').fetchall()

    lists = {}

    for k, g in groupby(todos, key=lambda t: t['title']):
        lists[k] = list(g)

    conn.close()
    return render_template('index.html', lists=lists)

ファイルを保存して閉じます。

get_db_connection()関数は、database.dbデータベースファイルへの接続を開き、row_factory属性をsqlite3.Rowに設定します。 このようにして、名前に基づいて列にアクセスできます。 これは、データベース接続が通常のPythonディクショナリのように動作する行を返すことを意味します。 最後に、この関数は、データベースへのアクセスに使用するconn接続オブジェクトを返します。

index()ビュー機能で、データベース接続を開き、次のSQLクエリを実行します。

SELECT i.content, l.title FROM items i JOIN lists l ON i.list_id = l.id ORDER BY l.title;

次に、fetchall()メソッドを使用して結果を取得し、todosという変数にデータを保存します。

このクエリでは、SELECTを使用して、itemsテーブルとlistsテーブルの両方を(テーブルと結合して)アイテムのコンテンツとアイテムが属するリストのタイトルを取得します。 itemsのエイリアスiおよびlistsのエイリアスl)。 ONキーワードの後に結合条件i.list_id = l.idを指定すると、itemsテーブルの各行と、listsテーブルのすべての行が取得されます。 itemsテーブルの]列は、listsテーブルのidと一致します。 次に、ORDER BYを使用して、リストのタイトルで結果を並べ替えます。

このクエリをよりよく理解するには、flask_todoディレクトリでPythonREPLを開きます。

python

SQLクエリを理解するには、次の小さなプログラムを実行してtodos変数の内容を調べます。

from app import get_db_connection
conn = get_db_connection()
todos = conn.execute('SELECT i.content, l.title FROM items i JOIN lists l \
ON i.list_id = l.id ORDER BY l.title;').fetchall()
for todo in todos:
    print(todo['title'], ':', todo['content'])

最初にapp.pyファイルからget_db_connectionをインポートし、次に接続を開いてクエリを実行します(これは、app.pyファイルにあるSQLクエリと同じであることに注意してください)。 forループでは、リストのタイトルと各ToDo項目の内容を出力します。

出力は次のようになります。

OutputHome : Buy fruit
Home : Cook dinner
Study : Learn Flask
Study : Learn SQLite
Work : Morning meeting

CTRL + Dを使用してREPLを閉じます。

SQL結合がどのように機能し、クエリが何を達成するかを理解したところで、app.pyファイルのindex()ビュー関数に戻りましょう。 todos変数を宣言した後、次のコードを使用して結果をグループ化します。

lists = {}

for k, g in groupby(todos, key=lambda t: t['title']):
    lists[k] = list(g)

最初にlistsという空の辞書を宣言し、次にforループを使用して、todos変数の結果をリストのタイトルでグループ化します。 itertools標準ライブラリからインポートしたgroupby()関数を使用します。 この関数は、todos変数の各項目を調べ、forループの各キーの結果のグループを生成します。

kは、keyに渡した関数を使用して抽出されたリストタイトル(つまり、HomeStudyWork)を表します。 ]groupby()関数のパラメーター。 この場合、関数はlambda t: t['title']であり、To Do項目を受け取り、リストのタイトルを返します(前のforループのtodo['title']で行ったように)。 gは、各リストタイトルのやること項目を含むグループを表します。 たとえば、最初の反復では、k'Home'になり、gはアイテム'Buy fruit'を含む反復可能になります。および'Cook dinner'

これにより、リストとアイテム間の1対多の関係を表すことができます。各リストのタイトルには、いくつかのToDoアイテムがあります。

app.pyファイルを実行し、forループの実行が終了すると、listsは次のようになります。

Output{'Home': [<sqlite3.Row object at 0x7f9f58460950>,
          <sqlite3.Row object at 0x7f9f58460c30>],
 'Study': [<sqlite3.Row object at 0x7f9f58460b70>,
           <sqlite3.Row object at 0x7f9f58460b50>],
 'Work': [<sqlite3.Row object at 0x7f9f58460890>]}

sqlite3.Rowオブジェクトには、index()関数のSQLクエリを使用してitemsテーブルから取得したデータが含まれます。 このデータをより適切に表現するために、listsディクショナリを調べて、各リストとそのアイテムを表示するプログラムを作成しましょう。

flask_todoディレクトリにあるlist_example.pyというファイルを開きます。

nano list_example.py

次に、次のコードを追加します。

フラスコ_todo/list_example.py

from itertools import groupby
from app import get_db_connection

conn = get_db_connection()
todos = conn.execute('SELECT i.content, l.title FROM items i JOIN lists l \
                        ON i.list_id = l.id ORDER BY l.title;').fetchall()

lists = {}

for k, g in groupby(todos, key=lambda t: t['title']):
    lists[k] = list(g)

for list_, items in lists.items():
    print(list_)
    for item in items:
        print('    ', item['content'])

ファイルを保存して閉じます。

これは、index()ビュー機能の内容と非常によく似ています。 ここでの最後のforループは、listsディクショナリがどのように構成されているかを示しています。 最初に辞書の項目を調べ、リストのタイトル(list_変数にあります)を印刷し、次にリストに属するTo Do項目の各グループを調べて、項目のコンテンツ値を印刷します。

list_example.pyプログラムを実行します。

python list_example.py

list_example.pyの出力は次のとおりです。

OutputHome
     Buy fruit
     Cook dinner
Study
     Learn Flask
     Learn SQLite
Work
     Morning meeting

index()関数の各部分を理解したところで、ベーステンプレートを作成し、return render_template('index.html', lists=lists)行を使用してレンダリングしたindex.htmlファイルを作成しましょう。

flask_todoディレクトリに、templatesディレクトリを作成し、その中にbase.htmlというファイルを開きます。

mkdir templates
nano templates/base.html

base.html内に次のコードを追加します。ここでは、Bootstrapを使用していることに注意してください。 FlaskのHTMLテンプレートに慣れていない場合は、 Python3でFlaskを使用してWebアプリケーションを作成する方法のステップ3を参照してください。

フラスコ_todo/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')}}">FlaskTodo</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コードへのリンクです。 詳細については、ブートストラップドキュメントを確認してください。

次に、このbase.htmlファイルを拡張するindex.htmlファイルを作成します。

nano templates/index.html

次のコードをindex.htmlに追加します。

フラスコ_todo/templates / index.html

{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Welcome to FlaskTodo {% endblock %}</h1>
    {% for list, items in lists.items() %}
        <div class="card" style="width: 18rem; margin-bottom: 50px;">
            <div class="card-header">
                <h3>{{ list }}</h3>
            </div>
            <ul class="list-group list-group-flush">
                {% for item in items %}
                    <li class="list-group-item">{{ item['content'] }}</li>
                {% endfor %}
            </ul>
        </div>
    {% endfor %}
{% endblock %}

ここでは、forループを使用して、listsディクショナリの各項目を調べ、リストタイトルを<h3>タグ内のカードヘッダーとして表示してから、リストを使用します。 <li>タグのリストに属する各ToDo項目を表示するグループ。 これは、list_example.pyプログラムで説明されているのと同じルールに従います。

ここで、Flaskが必要とする環境変数を設定し、次のコマンドを使用してアプリケーションを実行します。

export FLASK_APP=app
export FLASK_ENV=development
flask run

開発サーバーが実行されたら、ブラウザでURLhttp://127.0.0.1:5000/にアクセスできます。 「WelcometoFlaskTodo」とリストアイテムが掲載されたWebページが表示されます。

これで、CTRL + Cと入力して、開発サーバーを停止できます。

ToDoリストと各リストの項目を表示するFlaskアプリケーションを作成しました。 次のステップでは、新しいToDoアイテムを作成するための新しいページを追加します。

ステップ3—新しいToDoアイテムを追加する

このステップでは、To Doアイテムを作成するための新しいルートを作成し、データベーステーブルにデータを挿入し、アイテムをそれらが属するリストに関連付けます。

まず、app.pyファイルを開きます。

nano app.py

次に、ファイルの最後にcreate()というビュー関数を使用して新しい/createルートを追加します。

フラスコ_todo/app.py

...
@app.route('/create/', methods=('GET', 'POST'))
def create():
    conn = get_db_connection()
    lists = conn.execute('SELECT title FROM lists;').fetchall()

    conn.close()
    return render_template('create.html', lists=lists)

ファイルを保存して閉じます。

このルートを使用してWebフォームを介してデータベースに新しいデータを挿入するため、app.route()デコレータでmethods=('GET', 'POST')を使用してGETリクエストとPOSTリクエストの両方を許可します。 create()ビュー機能では、データベース接続を開き、データベースで使用可能なすべてのリストタイトルを取得し、接続を閉じて、create.htmlテンプレートをレンダリングしてリストタイトルを渡します。

次に、create.htmlという名前の新しいテンプレートファイルを開きます。

nano templates/create.html

次のHTMLコードをcreate.htmlに追加します。

フラスコ_todo/templates / create.html

{% extends 'base.html' %}

{% block content %}
<h1>{% block title %} Create a New Item {% endblock %}</h1>

<form method="post">
    <div class="form-group">
        <label for="content">Content</label>
        <input type="text" name="content"
               placeholder="Todo content" class="form-control"
               value="{{ request.form['content'] }}"></input>
    </div>

    <div class="form-group">
        <label for="list">List</label>
        <select class="form-control" name="list">
            {% for list in lists %}
                {% if list['title'] == request.form['list'] %}
                    <option value="{{ request.form['list'] }}" selected>
                        {{ request.form['list'] }}
                    </option>
                {% else %}
                    <option value="{{ list['title'] }}">
                        {{ list['title'] }}
                    </option>
                {% endif %}
            {% endfor %}
        </select>
    </div>
    <div class="form-group">
        <button type="submit" class="btn btn-primary">Submit</button>
    </div>
</form>
{% endblock %}

ファイルを保存して閉じます。

request.formを使用して、フォームの送信で問題が発生した場合(たとえば、やることコンテンツが提供されなかった場合)に保存されているフォームデータにアクセスします。 <select>要素では、create()関数でデータベースから取得したリストをループします。 リストタイトルがrequest.formに保存されているものと等しい場合、選択されたオプションはそのリストタイトルです。それ以外の場合、リストタイトルは通常の選択されていない<option>タグで表示されます。

次に、ターミナルで、Flaskアプリケーションを実行します。

flask run

次に、ブラウザでhttp://127.0.0.1:5000/createにアクセスすると、新しいTo Doアイテムを作成するためのフォームが表示されます。ブラウザから送信されるPOSTリクエストを処理するコードがないため、フォームはまだ機能しないことに注意してください。フォームを送信するとき。

CTRL + Cと入力して、開発サーバーを停止します。

次に、POSTリクエストを処理するためのコードをcreate()関数に追加し、フォーム関数を正しく作成して、app.pyを開きます。

nano app.py

次に、create()関数を次のように編集します。

フラスコ_todo/app.py

...
@app.route('/create/', methods=('GET', 'POST'))
def create():
    conn = get_db_connection()

    if request.method == 'POST':
        content = request.form['content']
        list_title = request.form['list']

        if not content:
            flash('Content is required!')
            return redirect(url_for('index'))

        list_id = conn.execute('SELECT id FROM lists WHERE title = (?);',
                                 (list_title,)).fetchone()['id']
        conn.execute('INSERT INTO items (content, list_id) VALUES (?, ?)',
                     (content, list_id))
        conn.commit()
        conn.close()
        return redirect(url_for('index'))

    lists = conn.execute('SELECT title FROM lists;').fetchall()

    conn.close()
    return render_template('create.html', lists=lists)

ファイルを保存して閉じます。

request.method == 'POST'条件内で、フォームデータからToDoアイテムのコンテンツとリストのタイトルを取得します。 コンテンツが送信されなかった場合は、flash()機能を使用してユーザーにメッセージを送信し、インデックスページにリダイレクトします。 この条件がトリガーされなかった場合は、SELECTステートメントを実行して、提供されたリストタイトルからリストIDを取得し、list_idという変数に保存します。 次に、INSERT INTOステートメントを実行して、新しいToDo項目をitemsテーブルに挿入します。 list_id変数を使用して、アイテムをそれが属するリストにリンクします。 最後に、トランザクションをコミットし、接続を閉じて、インデックスページにリダイレクトします。

最後のステップとして、ナビゲーションバーに/createへのリンクを追加し、その下に点滅するメッセージを表示します。これを行うには、base.htmlを開きます。

nano templates/base.html

create()表示機能にリンクする新しい<li>ナビゲーション項目を追加してファイルを編集します。 次に、contentブロックの上にあるforループを使用して、フラッシュされたメッセージを表示します。 これらはget_flashed_messages()Flask関数で利用できます。

フラスコ_todo/templates / base.html

<nav class="navbar navbar-expand-md navbar-light bg-light">
    <a class="navbar-brand" href="{{ url_for('index')}}">FlaskTodo</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="{{ url_for('create') }}">New</a>
        </li>

        <li class="nav-item active">
            <a class="nav-link" href="#">About</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>

ファイルを保存して閉じます。

次に、ターミナルで、Flaskアプリケーションを実行します。

flask run

/createへの新しいリンクがナビゲーションバーに表示されます。 このページに移動して、コンテンツのない新しいTo Doアイテムを追加しようとすると、コンテンツが必要です!というメッセージが点滅します。 コンテンツフォームに入力すると、新しいToDoアイテムがインデックスページに表示されます。

このステップでは、新しいTo Doアイテムを作成し、それらをデータベースに保存する機能を追加しました。

このプロジェクトのソースコードは、このリポジトリにあります。

結論

これで、やることリストとアイテムを管理するためのアプリケーションができました。 各リストには複数のToDo項目があり、各ToDo項目は1対多の関係にある単一のリストに属しています。 FlaskとSQLiteを使用して複数の関連データベーステーブルを管理する方法、外部キーを使用する方法、およびSQLite結合を使用してWebアプリケーションの2つのテーブルから関連データを取得して表示する方法を学習しました。

さらに、groupby()関数を使用して結果をグループ化し、データベースに新しいデータを挿入し、データベーステーブルの行をそれらが関連するテーブルに関連付けました。 外部キーとデータベースの関係について詳しくは、SQLiteのドキュメントをご覧ください。

PythonFrameworkコンテンツの詳細も読むことができます。 sqlite3 Pythonモジュールを確認したい場合は、 Python3でsqlite3モジュールを使用する方法に関するチュートリアルをお読みください。