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

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

著者は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アイテムを作成し、SammyJoの両方に割り当てることができます。各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アプリケーションに多対多の関係を追加する方法を示すために、前のチュートリアルのアプリケーションコードを使用します。これは、 FlaskSQLiteを使用して構築された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ファイルには、リストを保存するためのlistsHomeStudyなど)とitemsの2つのテーブルがあります。やること項目(Do the dishesLearn 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 lightingSammyJoの両方に割り当てたい場合、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 1Sammy)の譲受人に関連しています。 2行目では、同じ項目がID 2Jo)の担当者にも関連しています。 これは、やること項目がSammyJoの両方に割り当てられていることを意味します。 同様に、各担当者を複数のアイテムに割り当てることができます。

次に、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()を使用して接続を閉じます。

これにより、SammyJoCharlie、および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変数は、SELECTSQLクエリの結果を保持します。 このクエリは、assigneesテーブル(aにエイリアスされてクエリを短縮する)から担当者のID(a.id)と担当者の名前(a.name)を取得します)。 クエリは、条件a.id = i_a.assignee_iditem_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)

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

これは、ステップ3list_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チュートリアルを参照してください。