FlaskおよびSQLiteで多対多のデータベース関係を使用する方法
著者はCOVID-19救済基金を選択し、 Write forDOnationsプログラムの一環として寄付を受け取りました。
序章
Flask は、Python言語を使用してWebアプリケーションを構築するためのフレームワークであり、 SQLite は、Pythonでアプリケーションデータを保存するために使用できるデータベースエンジンです。 このチュートリアルでは、FlaskとSQLiteを使用して構築されたアプリケーションに、多対多の関係を追加して変更します。
このチュートリアルは個別に実行できますが、FlaskおよびSQLiteを使用した1対多データベースの関係でアイテムを変更する方法チュートリアルの続きでもあります。 ToDoアプリケーションの例を使用した1対多の関係。 このアプリケーションを使用すると、ユーザーは新しいTo Doアイテムを追加したり、アイテムをさまざまなリストに分類したり、アイテムを変更したりできます。
多対多データベース関係は、各テーブルのレコードが他のテーブルの複数のレコードを参照できる2つのテーブル間の関係です。 たとえば、ブログでは、投稿用のテーブルは、作成者を保存するためのテーブルと多対多の関係を持つことができます。 各投稿は多くの作成者を参照でき、各作成者は多くの投稿を参照できます。 各投稿には多くのの作成者を含めることができ、各作成者は多くのの投稿を書き込むことができます。 したがって、投稿と作成者の間には多対多の関係があります。 別の例として、ソーシャルメディアアプリケーションでは、各投稿に多くのハッシュタグがあり、各ハッシュタグに多くの投稿がある場合があります。
チュートリアルが終了するまでに、アプリケーションには、さまざまなユーザーにToDoアイテムを割り当てるための新機能が追加されます。 assigneesという言葉でto-dosを割り当てられたユーザーを指します。 たとえば、Cleaning the kitchen
の家庭用ToDoアイテムを作成し、Sammy
とJo
の両方に割り当てることができます。各ToDoには多くのアイテムを含めることができます。 譲受人(つまり、Sammy
およびJo
)。 また、各ユーザーは多くののやることを割り当てることができます(つまり、Sammy
には複数のやることを割り当てることができます)。これは、to-間の多対多の関係です。アイテムと譲受人を行います。
このチュートリアルの最後に、アプリケーションには、リストされた担当者の名前が記載された Assignedtoタグが含まれます。
前提条件
このガイドに従う前に、次のものが必要です。
- ローカルのPython3プログラミング環境については、 Python3シリーズのローカルプログラミング環境をインストールしてセットアップする方法のチュートリアルに従ってください。 このチュートリアルでは、プロジェクトディレクトリを
flask_todo
と呼びます。 - (オプション)ステップ1 では、このチュートリアルで作業するToDoアプリケーションのクローンを作成するオプションがあります。 ただし、オプションで、FlaskおよびSQLiteとの1対多のデータベース関係の使用方法およびFlaskおよびSQLiteとの1対多のデータベース関係のアイテムの変更方法を使用できます。 ]。 このページから最終コードにアクセスできます。
- (オプション)ルートの作成、HTMLテンプレートのレンダリング、SQLiteデータベースへの接続などの基本的なFlaskの概念の理解。 これらの概念に精通していない場合は、 Python3でFlaskを使用してWebアプリケーションを作成する方法とPython3でsqlite3モジュールを使用する方法を確認してください。
ステップ1—Webアプリケーションのセットアップ
このステップでは、変更の準備ができたToDoアプリケーションをセットアップします。 また、データベーススキーマを確認して、データベースの構造を理解します。 前提条件セクションのチュートリアルに従い、ローカルマシンにコードと仮想環境が残っている場合は、この手順をスキップできます。
Flask Webアプリケーションに多対多の関係を追加する方法を示すために、前のチュートリアルのアプリケーションコードを使用します。これは、 Flask 、SQLiteを使用して構築されたToDo管理Webアプリケーションです。 ]、およびブートストラップフレームワーク。 このアプリケーションを使用すると、ユーザーは新しいTo Doを作成したり、既存のTo Doを変更および削除したり、ToDoを完了としてマークしたりできます。
次のコマンドを使用して、リポジトリのクローンを作成し、flask-todo-2
からflask_todo
に名前を変更します。
git clone https://github.com/do-community/flask-todo-2 flask_todo
flask_todo
に移動します。
cd flask_todo
次に、新しい仮想環境を作成します。
python -m venv env
環境をアクティブにします。
source env/bin/activate
Flaskをインストールします:
pip install Flask
次に、init_db.py
プログラムを使用してデータベースを初期化します。
python init_db.py
次に、次の環境変数を設定します。
export FLASK_APP=app export FLASK_ENV=development
FLASK_APP
は、現在開発中のアプリケーションを示します。この場合はapp.py
です。 FLASK_ENV
はモードを指定します。開発モードの場合は、development
に設定します。 これにより、アプリケーションをデバッグできます。 (実稼働環境ではこのモードを使用しないでください。)
次に、開発サーバーを実行します。
flask run
ブラウザにアクセスすると、アプリケーションは次のURLで実行されます:http://127.0.0.1:5000/
。
開発サーバーを停止するには、CTRL + C
を使用します。
次に、データベーススキーマを調べて、テーブル間の現在の関係を理解します。 schema.sql
ファイルの内容に精通している場合は、次の手順にスキップできます。
schema.sql
ファイルを開きます。
nano schema.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, done INTEGER NOT NULL DEFAULT 0, FOREIGN KEY (list_id) REFERENCES lists (id) );
schema.sql
ファイルには、リストを保存するためのlists
(Home
やStudy
など)とitems
の2つのテーブルがあります。やること項目(Do the dishes
やLearn Flask
など)の保存。
lists
テーブルには次の列があります。
id
:リストのID。created
:リストの作成日。title
:リストのタイトル。
items
テーブルには次の列があります。
id
:アイテムのID。list_id
:アイテムが属するリストのID。created
:アイテムの作成日。content
:アイテムのコンテンツ。done
:アイテムの状態。値0
はアイテムがまだ完了していないことを示し、1
はアイテムの完了を示します。
items
テーブルには、外部キー制約があり、list_id
列はlists
親のid
列を参照します。テーブル。 これは、アイテムとリストの間の1対多の関係であり、リストに複数のアイテムを含めることができ、アイテムが1つのリストに属していることを示します。
FOREIGN KEY (list_id) REFERENCES lists (id)
次のステップでは、多対多の関係を使用して、2つのテーブル間にリンクを作成します。
ステップ2—担当者テーブルを追加する
このステップでは、多対多の関係と結合テーブルを実装する方法を確認します。 次に、担当者を保存するための新しいテーブルを追加します。
多対多の関係は、テーブル内の各アイテムが他のテーブル内の多くの関連アイテムを持っている2つのテーブルをリンクします。
次のように、やること項目の簡単なテーブルがあるとします。
Items +----+-------------------+ | id | content | +----+-------------------+ | 1 | Buy eggs | | 2 | Fix lighting | | 3 | Paint the bedroom | +----+-------------------+
そして、そのような譲受人のための表:
assignees +----+------+ | id | name | +----+------+ | 1 | Sammy| | 2 | Jo | +----+------+
To Do Fix lighting
をSammy
とJo
の両方に割り当てたい場合、items
テーブルに新しい行を追加することでこれを行うことができます。そのようです:
items +----+-------------------+-----------+ | id | content | assignees | +----+-------------------+-----------+ | 1 | Buy eggs | | | 2 | Fix lighting | 1, 2 | | 3 | Paint the bedroom | | +----+-------------------+-----------+
各列には1つの値しかないため、これは間違ったアプローチです。 複数の値がある場合、データの追加や更新などの基本的な操作は面倒で時間がかかります。 代わりに、関連するテーブルの主キーを参照する3番目のテーブルが必要です。このテーブルは結合テーブルと呼ばれることが多く、各テーブルの各アイテムのIDを格納します。
アイテムと担当者をリンクする結合テーブルの例を次に示します。
item_assignees +----+---------+-------------+ | id | item_id | assignee_id | +----+---------+-------------+ | 1 | 2 | 1 | | 2 | 2 | 2 | +----+---------+-------------+
最初の行で、ID 2
(つまり、Fix lighting
)のアイテムは、ID 1
(Sammy
)の譲受人に関連しています。 2行目では、同じ項目がID 2
(Jo
)の担当者にも関連しています。 これは、やること項目がSammy
とJo
の両方に割り当てられていることを意味します。 同様に、各担当者を複数のアイテムに割り当てることができます。
次に、To Doアプリケーションのデータベースを変更して、担当者を格納するためのテーブルを追加します。
まず、schema.sql
を開いて、assignees
という名前の新しいテーブルを追加します。
nano schema.sql
assignees
テーブルがすでに存在する場合は、それを削除する行を追加します。 これは、異なる列を持つ既存のassignees
テーブルなど、データベースを再起動するときに発生する可能性のある将来の問題を回避するためです。同じスキーマに従わない場合、コードが予期せず破損する可能性があります。 テーブルのSQLコードも追加します。
フラスコ_todo/schema.sql
DROP TABLE IF EXISTS assignees; 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, done INTEGER NOT NULL DEFAULT 0, FOREIGN KEY (list_id) REFERENCES lists (id) ); CREATE TABLE assignees ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL );
ファイルを保存して閉じます。
この新しいassignees
テーブルには、次の列があります。
id
:担当者のID。name
:担当者の名前。
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') ) cur.execute("INSERT INTO assignees (name) VALUES (?)", ('Sammy',)) cur.execute("INSERT INTO assignees (name) VALUES (?)", ('Jo',)) cur.execute("INSERT INTO assignees (name) VALUES (?)", ('Charlie',)) cur.execute("INSERT INTO assignees (name) VALUES (?)", ('Ashley',)) connection.commit() connection.close()
ファイルを保存して閉じます。
強調表示された行で、カーソルオブジェクトを使用してINSERT
SQLステートメントを実行し、4つの名前をassignees
テーブルに挿入します。 execute()メソッドで?
プレースホルダーを使用し、担当者の名前を含むタプルを渡して、データベースにデータを安全に挿入します。 次に、connection.commit()
を使用してトランザクションをコミットし、connection.close()
を使用して接続を閉じます。
これにより、Sammy
、Jo
、Charlie
、およびAshley
という名前の4人の担当者がデータベースに追加されます。
init_db.py
プログラムを実行して、データベースを再初期化します。
python init_db.py
これで、担当者をデータベースに保存するためのテーブルができました。 次に、結合テーブルを追加して、アイテムと担当者の間に多対多の関係を作成します。
ステップ3—多対多の結合テーブルを追加する
このステップでは、結合テーブルを使用して、ToDoアイテムを担当者にリンクします。 まず、データベーススキーマファイルを編集して新しい結合テーブルを追加し、データベース初期化プログラムを編集していくつかの割り当てを追加し、次にデモプログラムを使用して各ToDoの担当者を表示します。
schema.sql
を開いて、新しいテーブルを追加します。
nano schema.sql
テーブルはアイテムと担当者を結合するため、item_assignees
と呼びます。 テーブルがすでに存在する場合は削除する行を追加してから、テーブル自体のSQLコードを追加します。
フラスコ_todo/schema.sql
DROP TABLE IF EXISTS assignees; DROP TABLE IF EXISTS lists; DROP TABLE IF EXISTS items; DROP TABLE IF EXISTS item_assignees; 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, done INTEGER NOT NULL DEFAULT 0, FOREIGN KEY (list_id) REFERENCES lists (id) ); CREATE TABLE assignees ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL ); CREATE TABLE item_assignees ( id INTEGER PRIMARY KEY AUTOINCREMENT, item_id INTEGER, assignee_id INTEGER, FOREIGN KEY(item_id) REFERENCES items(id), FOREIGN KEY(assignee_id) REFERENCES assignees(id) );
ファイルを保存して閉じます。
この新しいitem_assignees
テーブルには、次の列があります。
id
:やることと譲受人の間の関係を確立するエントリのID。 各行は関係を表します。item_id
:対応するassignee_id
とともに担当者に割り当てられるToDoアイテムのID。assignee_id
:対応するitem_id
でアイテムが割り当てられる譲受人のID。
item_assignees
テーブルにも2つの外部キー制約があります。1つはitem_id
列をitems
テーブルのid
列にリンクし、もう1つはassignee_id
列とassignees
テーブルのid
列。
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') ) cur.execute("INSERT INTO assignees (name) VALUES (?)", ('Sammy',)) cur.execute("INSERT INTO assignees (name) VALUES (?)", ('Jo',)) cur.execute("INSERT INTO assignees (name) VALUES (?)", ('Charlie',)) cur.execute("INSERT INTO assignees (name) VALUES (?)", ('Ashley',)) # Assign "Morning meeting" to "Sammy" cur.execute("INSERT INTO item_assignees (item_id, assignee_id) VALUES (?, ?)", (1, 1)) # Assign "Morning meeting" to "Jo" cur.execute("INSERT INTO item_assignees (item_id, assignee_id) VALUES (?, ?)", (1, 2)) # Assign "Morning meeting" to "Ashley" cur.execute("INSERT INTO item_assignees (item_id, assignee_id) VALUES (?, ?)", (1, 4)) # Assign "Buy fruit" to "Sammy" cur.execute("INSERT INTO item_assignees (item_id, assignee_id) VALUES (?, ?)", (2, 1)) connection.commit() connection.close()
強調表示されたコードでは、item_assignees
結合テーブルに挿入することにより、ToDo項目を担当者に割り当てます。 assignee_id
値に対応するIDを使用して、担当者に割り当てるToDo項目のitem_id
を挿入します。 最初に強調表示されている行で、IDが1
のToDoアイテムMorning meeting
を、IDが1
。 残りの行は同じパターンに従います。 ここでも、?
プレースホルダーを使用して、タプルに挿入する値をcur.execute()
メソッドに安全に渡します。
ファイルを保存して閉じます。
init_db.py
プログラムを実行して、データベースを再初期化します。
python init_db.py
データベースにあるToDo項目を表示するlist_example.py
プログラムを実行します。
python list_example.py
出力は次のとおりです。
OutputHome Buy fruit | id: 2 | done: 0 Cook dinner | id: 3 | done: 0 Study Learn Flask | id: 4 | done: 0 Learn SQLite | id: 5 | done: 0 Work Morning meeting | id: 1 | done: 0
これにより、ToDo項目が属するリストの下に表示されます。 各アイテムのコンテンツ、ID、および完了したかどうかがわかります(0
はアイテムがまだ完了していないことを意味し、1
は完了したことを意味します)。 次に、各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.id, i.done, 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']): # Create an empty list for items items = [] # Go through each to-do item row in the groupby() grouper object for item in g: # Get the assignees of the current to-do item assignees = conn.execute('SELECT a.id, a.name FROM assignees a \ JOIN item_assignees i_a \ ON a.id = i_a.assignee_id \ WHERE i_a.item_id = ?', (item['id'],)).fetchall() # Convert the item row into a dictionary to add assignees item = dict(item) item['assignees'] = assignees items.append(item) # Build the list of dictionaries # the list's name (ex: Home/Study/Work) as the key # and a list of dictionaries of to-do items # belonging to that list as the value lists[k] = list(items) for list_, items in lists.items(): print(list_) for item in items: assignee_names = ', '.join(a['name'] for a in item['assignees']) print(' ', item['content'], '| id:', item['id'], '| done:', item['done'], '| assignees:', assignee_names)
ファイルを保存して閉じます。
groupby()関数を使用して、ToDoアイテムをそれらが属するリストのタイトルでグループ化します。 (詳細については、FlaskおよびSQLiteで1対多のデータベース関係を使用する方法のステップ2を参照してください。)グループ化プロセスの実行中に、[ X198X] 。アイテムのID、コンテンツ、担当者など、すべてのToDoアイテムデータを保持します。 次に、for item in g
ループで、各To Doアイテムを調べ、アイテムの担当者を取得して、assignees
変数に保存します。
assignees
変数は、SELECT
SQLクエリの結果を保持します。 このクエリは、assignees
テーブル(a
にエイリアスされてクエリを短縮する)から担当者のID(a.id
)と担当者の名前(a.name
)を取得します)。 クエリは、条件a.id = i_a.assignee_id
でitem_assignees
結合テーブル(別名i_a
)を使用してIDと名前を結合します。ここで、i_a.item_id
の値は現在の値と同じです。アイテムのID(item['id']
)。 次に、 fetchall()メソッドを使用して、結果をリストとして取得します。
通常のsqlite3.Rowオブジェクトは割り当てをサポートしていないため、item = dict(item)
の行を使用して、アイテムを辞書に変換します。割り当ては、アイテムに割り当て先を追加する必要があります。 次に、item['assignees'] = assignees
という行を使用して、新しいキー'assignees'
をitem
ディクショナリに追加し、アイテムのディクショナリから直接アイテムの担当者にアクセスします。 次に、変更したアイテムをitems
リストに追加します。 すべてのデータを保持する辞書のリストを作成します。 各辞書キーはやることリストのタイトルであり、その値はそれに属するすべての項目のリストです。
結果を印刷するには、for list_, items in lists.items()
ループを使用して、各ToDoリストのタイトルとそれに属するToDoアイテムを調べ、リストのタイトル(list_
)を印刷してから、リストのやること項目をループします。 assignee_names
という名前の変数を追加しました。この変数の値は、 join()メソッドを使用して、ジェネレーター式a['name'] for a in item['assignees']
の項目間を結合します。これは、item['assignees']
リスト内の各譲受人のデータから譲受人の名前(a['name']
)を抽出します。 この結合された担当者名のリストは、print()
関数でToDoアイテムの残りのデータとともに印刷します。
list_example.py
プログラムを実行します。
python list_example.py
出力は次のとおりです(担当者が強調表示されています)。
OutputHome Buy fruit | id: 2 | done: 0 | assignees: Sammy Cook dinner | id: 3 | done: 0 | assignees: Study Learn Flask | id: 4 | done: 0 | assignees: Learn SQLite | id: 5 | done: 0 | assignees: Work Morning meeting | id: 1 | done: 0 | assignees: Sammy, Jo, Ashley
これで、各ToDo項目の担当者を残りのデータとともに表示できます。
これで、各ToDo項目の担当者名が表示されました。 次に、これを使用して、Webアプリケーションのインデックスページの各ToDo項目の下に名前を表示します。
ステップ4—インデックスページに担当者を表示する
このステップでは、To Do管理アプリケーションのインデックスページを変更して、各ToDo項目の担当者を表示します。 まず、Flaskアプリケーションのコードを含むapp.py
ファイルを編集し、次にindex.html
テンプレートファイルを編集して、インデックスページの各ToDo項目の下に担当者を表示します。
まず、app.py
を開いて、index()
ビュー機能を編集します。
nano app.py
次のように関数を変更します。
フラスコ_todo/app.py
@app.route('/') def index(): conn = get_db_connection() todos = conn.execute('SELECT i.id, i.done, 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']): # Create an empty list for items items = [] # Go through each to-do item row in the groupby() grouper object for item in g: # Get the assignees of the current to-do item assignees = conn.execute('SELECT a.id, a.name FROM assignees a \ JOIN item_assignees i_a \ ON a.id = i_a.assignee_id \ WHERE i_a.item_id = ?', (item['id'],)).fetchall() # Convert the item row into a dictionary to add assignees item = dict(item) item['assignees'] = assignees items.append(item) # Build the list of dictionaries # the list's name (ex: Home/Study/Work) as the key # and a list of dictionaries of to-do items # belonging to that list as the value lists[k] = list(items) conn.close() return render_template('index.html', lists=lists)
ファイルを保存して閉じます。
これは、ステップ3のlist_example.py
デモンストレーションプログラムで使用したものと同じコードです。 これにより、lists
変数には、index.html
テンプレートファイル内の担当者名にアクセスするために使用する担当者データを含む、必要なすべてのデータが含まれます。
index.html
ファイルを開いて、各項目の後に担当者名を追加します。
nano templates/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" {% if item['done'] %} style="text-decoration: line-through;" {% endif %} >{{ item['content'] }} {% if not item ['done'] %} {% set URL = 'do' %} {% set BUTTON = 'Do' %} {% else %} {% set URL = 'undo' %} {% set BUTTON = 'Undo' %} {% endif %} <div class="row"> <div class="col-12 col-md-3"> <form action="{{ url_for(URL, id=item['id']) }}" method="POST"> <input type="submit" value="{{ BUTTON }}" class="btn btn-success btn-sm"> </form> </div> <div class="col-12 col-md-3"> <a class="btn btn-warning btn-sm" href="{{ url_for('edit', id=item['id']) }}">Edit</a> </div> <div class="col-12 col-md-3"> <form action="{{ url_for('delete', id=item['id']) }}" method="POST"> <input type="submit" value="Delete" class="btn btn-danger btn-sm"> </form> </div> </div> <hr> {% if item['assignees'] %} <span style="color: #6a6a6a">Assigned to</span> {% for assignee in item['assignees'] %} <span class="badge badge-primary"> {{ assignee['name'] }} </span> {% endfor %} {% endif %} </li> {% endfor %} </ul> </div> {% endfor %} {% endblock %}
ファイルを保存して閉じます。
この変更により、<hr>
タグを使用して各アイテムの下に改行を追加しました。 アイテムに担当者がいる場合(if item['assignees']
ステートメントでわかります)、灰色のAssigned to
テキストを表示し、アイテムの担当者(つまり、item['assignees']
リスト)をループします。 )、バッジに担当者名(assignee['name']
)を表示します。
最後に、開発サーバーを実行します。
flask run
次に、インデックスページhttp://127.0.0.1:5000/
にアクセスします。
各ToDoアイテムに多数の担当者を含めることができるようになり、各担当者に複数のToDoを割り当てることができます。 インデックスページには、すべてのアイテムと各アイテムの担当者が表示されます。
このリポジトリから最終コードにアクセスできます。
結論
このチュートリアルでは、多対多の関係とは何か、FlaskおよびSQLite Webアプリケーションでの使用方法、テーブル間の結合方法、Pythonでのリレーショナルデータのグループ化方法について学習しました。
これで、ユーザーが新しいTo Doアイテムを作成し、アイテムを完了としてマークし、既存のアイテムを編集または削除し、新しいリストを作成できる完全なToDoアプリケーションができました。 また、各アイテムを異なる担当者に割り当てることができます。
PythonとFlaskを使用したWeb開発の詳細については、これらのFlaskチュートリアルを参照してください。