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

序章

Flask は、Python言語を使用してWebアプリケーションを構築するためのフレームワークです。 Flaskを使用すると、SQLiteをデータベースエンジンとして使用してアプリケーションデータを保存できます。

Markdown は、読みやすいテキスト形式でコンテンツを書き込むプロセスで一般的に使用されるマークアップ言語です。 Markdownを使用すると、見出し、リンク、画像などの機能を使用してプレーンテキストをフォーマットし、テキストをHTMLに変換できます。これには、これらのフォーマット機能が含まれます。 Markdownの使用方法については、Markdown構文標準を確認してください。

Python-Markdown は、MarkdownテキストをHTMLに変換できるPythonライブラリです。 これは主にMarkdown標準に準拠していますが、標準のMarkdown構文とはわずかな違いがあります。

このチュートリアルでは、Flask、SQLite、およびPython-Markdownを使用して、Markdownを使用したテキストのフォーマットをサポートする小さなメモを取るWebアプリケーションを構築します。 このアプリを使用すると、ユーザーは見出し、リンク、リスト、画像、その他の機能を備えたメモを表示、作成、フォーマットできます。 Bootstrapツールキットを使用してアプリケーションのスタイルを設定します。

前提条件

  • ローカルのPython3プログラミング環境。 Python3シリーズのローカルプログラミング環境をインストールおよびセットアップする方法のチュートリアルに従ってください。 このチュートリアルでは、プロジェクトディレクトリにflask_notesという名前を付けます。

  • ルートの作成、HTMLテンプレートのレンダリング、SQLiteデータベースへの接続などの基本的なFlaskの概念の理解。 これらの概念に精通していない場合は、 Python3でFlaskを使用してWebアプリケーションを作成する方法とPython3でsqlite3モジュールを使用する方法を確認してください。

ステップ1—依存関係を設定する

このステップでは、Python環境をアクティブ化し、pipパッケージインストーラーを使用してFlaskとPython-Markdownをインストールします。 次に、メモを保存するために使用するデータベースを作成し、それにサンプルデータを追加します。

まず、プログラミング環境をまだアクティブにしていない場合はアクティブにします。

  1. source env/bin/activate

プログラミング環境をアクティブにしたら、次のコマンドを使用してFlaskとPython-Markdownライブラリをインストールします。

  1. pip install flask markdown

次に、schema.sqlというデータベーススキーマファイルを作成します。このファイルには、notesテーブルを作成するためのSQLコマンドが含まれています。 flask_notesディレクトリ内のファイルを開きます。

  1. nano schema.sql

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

フラスコノート/スキーマ.sql
DROP TABLE IF EXISTS notes;

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

このSQLファイルでは、最初にnotesという名前の既存のテーブルを削除します。これにより、問題が発生する可能性があります。 これにより、notesテーブルがこのSQLで説明されているとおりになります。 これにより、これらのSQLコマンドを使用するたびにデータベースにあるすべてのコンテンツが削除されるため、このチュートリアルを終了して最終結果を試すまで、Webアプリケーションに重要なコンテンツを書き込まないようにしてください。

CREATE TABLE notesステートメントを使用して、次の列を持つnotesテーブルを作成します。

  • id主キーを表す整数。 データベースは、これに各エントリに一意の値を割り当てます(メモ)。
  • created:ノートの作成日。 メモがデータベースに追加された時刻が自動的に入力されます。
  • content:メモの内容。

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

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

  1. nano init_db.py

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

フラスコ_notes/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 notes (content) VALUES (?)", ('# The First Note',))
cur.execute("INSERT INTO notes (content) VALUES (?)", ('_Another note_',))
cur.execute("INSERT INTO notes (content) VALUES (?)", ('Visit [this page](..) for more tutorials.',))

connection.commit()
connection.close()

ここでは、最初にsqlite3モジュールをインポートします。 次に、このプログラムを実行すると作成されるdatabase.dbというファイルに接続します。 database.dbは、アプリケーションのすべてのデータを保持するデータベースです。 次に、schema.sqlファイルを開き、複数のSQLステートメントを同時に実行する executescript()メソッドを使用して実行します。 これにより、notesテーブルが作成されます。

カーソルオブジェクトを使用して、いくつかのINSERT SQLステートメントを実行し、3つのノートを作成します。 ここではMarkdown構文を使用しています。最初のメモは<h1>の見出しで、2番目のメモは斜体で、3番目のメモにはリンクが含まれています。 execute()メソッドで?プレースホルダーを使用し、メモの内容を含むタプルを渡して、データベースにデータを安全に挿入します。

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

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

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

  1. python init_db.py

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

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

ステップ2—インデックスページにメモを表示する

このステップでは、データベースに接続し、データベースにあるサンプルデータを表示するFlaskアプリケーションを作成します。 データベース内のマークダウンテキストをHTMLに変換してから、インデックスページにレンダリングします。

まず、flask_notesディレクトリ内にapp.pyアプリケーションファイルを作成します。

  1. nano app.py

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

フラスコノート/app.py
import sqlite3
import markdown
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

最初に、sqlite3モジュール、markdownパッケージ、およびFlaskヘルパーをインポートします。

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

その後、次のコードスニペットを追加します。

フラスコノート/app.py
#. . .

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

ここでは、Flaskアプリケーションオブジェクトを作成し、秘密鍵をセキュアセッションに設定します。

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

フラスコノート/app.py
#. . .

@app.route('/')
def index():
    conn = get_db_connection()
    db_notes = conn.execute('SELECT id, created, content FROM notes;').fetchall()
    conn.close()

    notes = []
    for note in db_notes:
       note = dict(note)
       note['content'] = markdown.markdown(note['content'])
       notes.append(note)

    return render_template('index.html', notes=notes)

index()関数はFlaskview関数で、特別な@app.routeデコレータを使用して装飾された関数です。 Flaskは、この関数の戻り値を、WebブラウザーなどのHTTPクライアントが表示するHTTP応答に変換します。

index()ビュー関数で、データベース接続を開き、SELECT SQLステートメントを実行して、notesのすべての行のID、作成日、およびコンテンツをフェッチします。 ] テーブル。 fetchall()メソッドを使用して、すべての行のリストを取得し、このデータをdb_notes変数に保存します。 次に、接続を閉じます。

メモの内容をMarkdownからHTMLに変換するには、notesという名前の新しい空のリストを作成します。 db_notesリストをループし、dict() Python関数を使用して、各ノートをsqlite3.Rowから通常のPython辞書に変換して割り当てを許可します。 次に、markdown.markdown()関数を使用して、note['content']の値をHTMLに変換します。 たとえば、markdown.markdown('#Hi')を呼び出すと、文字列'<h1>Hi</h1>'が返されます。これは、Markdownでは#<h1>の見出しを表すためです。 note['content']を変更した後、notesリストにメモを追加します。

最後に、index.htmlというテンプレートファイルをレンダリングして、notesリストを渡します。

すべての追加後、ファイルは次のようになります。

フラスコノート/app.py
import sqlite3
import markdown
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()
    db_notes = conn.execute('SELECT id, created, content FROM notes;').fetchall()
    conn.close()

    notes = []
    for note in db_notes:
       note = dict(note)
       note['content'] = markdown.markdown(note['content'])
       notes.append(note)

    return render_template('index.html', notes=notes)

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

次に、ベーステンプレートとindex.htmlテンプレートファイルを作成します。

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

  1. mkdir templates
  2. nano templates/base.html

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

フラスコノート/テンプレート/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')}}">FlaskNotes</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">
        {% for message in get_flashed_messages() %}
            <div class="alert alert-danger">{{ message }}</div>
        {% endfor %}
        {% 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コードへのリンクです。

<title>{% block title %} {% endblock %}</title>タグを使用すると、継承するテンプレートでカスタムタイトルを定義できます。 for message in get_flashed_messages()ループを使用して、警告やアラートなどのフラッシュされたメッセージを表示します。 {% block content %} {% endblock %}プレースホルダーは、継承するテンプレートがコンテンツを配置する場所であり、すべてのテンプレートに、この基本テンプレートが提供する追加のコードが含まれ、繰り返しを回避します。

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

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

  1. nano templates/index.html

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

フラスコノート/テンプレート/インデックス.html

{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Welcome to FlaskNotes {% endblock %}</h1>
    {% for note in notes %}
    <div class="card">
        <div class="card-body">
            <span class="badge badge-primary">#{{ note['id'] }}</span>
            <span class="badge badge-default">{{ note['created'] }}</span>
            <hr>
            <p>{{ note['content'] |safe }}</p>
        </div>
    </div>
    <hr>
    {% endfor %}
{% endblock %}

ここでは、base.htmlを拡張し、タイトルを定義し、forループを使用して、ブートストラップカードの各ノートを表示するノートを調べます。 index()ビュー機能で、HTMLに変換したノートのID、作成日、ノートの内容を表示します。

|safe Jinjaフィルターを使用します。これは、|を使用してコンテンツに適用します。 これは、Pythonで関数を呼び出すのと似ています(safe(note['content'])と同様の方法で)。 |safeフィルターを使用すると、ブラウザーでHTMLコードをレンダリングできます。適用されていない場合は、HTMLがプレーンテキストとして表示されます。 これは通常、「エスケープHTML」と呼ばれ、悪意のあるHTMLがブラウザで解釈されてクロスサイトスクリプティング(XSS)と呼ばれる危険なセキュリティの脆弱性が発生するのを防ぐセキュリティ機能です。 Python-Markdownライブラリは安全なHTMLを返すため、|safeフィルターを使用してブラウザーにレンダリングを許可できます。 許可するHTMLコードが安全で信頼できることが確実になるまで、このフィルターを使用しないでください。

詳細については、自動エスケープの制御に関するFlaskのドキュメントを参照してください。

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

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

  1. export FLASK_APP=app
  2. export FLASK_ENV=development
  3. flask run

FLASK_APP環境変数は、実行するアプリケーション(app.pyファイル)を指定します。 FLASK_ENV環境変数はモードを指定します。 developmentは、デバッガーが実行されている状態でアプリケーションが開発モードで実行されることを意味します(本番環境でこのモードを使用しないように注意してください)。 flask runコマンドを使用してアプリケーションを実行します。

ブラウザを開き、URLhttp://127.0.0.1:5000/を入力します。

Flask Notes Index

ここでは、各メモがプレーンテキストではなくHTMLとしてフォーマットおよびレンダリングされていることがわかります。

データベースに接続し、メモを取得し、そのコンテンツをMarkdownテキストからHTMLに変換して、インデックスページにレンダリングするFlaskアプリケーションを作成しました。 次に、ユーザーがMarkdown構文を使用して書き込むことができる新しいメモを追加できるようにするルートを追加します。

ステップ3—新しいメモを追加する

このステップでは、ユーザーが新しいメモを取ることができる新しいルートを追加します。 ユーザーはMarkdown構文を使用してメモを書くことができます。アプリケーションはメモをデータベースに保存し、適切な形式でインデックスページに表示します。 また、ユーザーをこの新しいページに移動するためのボタンをナビゲーションバーに追加します。

Webフォームを使用して、ユーザーがFlaskアプリケーションでデータを送信できるようにし、ユーザーが送信したデータをデータベースに保存します。

最初にapp.pyファイルを開いて、新しいルートを追加します。

  1. nano app.py

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

フラスコノート/app.py
#. . .

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

    if request.method == 'POST':
        content = request.form['content']
        if not content:
            flash('Content is required!')
            return redirect(url_for('index'))
        conn.execute('INSERT INTO notes (content) VALUES (?)', (content,))
        conn.commit()
        conn.close()
        return redirect(url_for('index'))

    return render_template('create.html')

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

ユーザーが条件request.method == 'POST'が真であることを意味するフォームを送信した場合、ユーザーが送信したメモのコンテンツをrequest.form['content']を使用して抽出し、contentという変数に保存します。 ]。 コンテンツが空の場合は、'Content is required!'メッセージをフラッシュし、ユーザーをインデックスページにリダイレクトします。 コンテンツが空でない場合は、INSERT SQLステートメントを使用して、メモのコンテンツをnotesテーブルに追加します。 変更をコミットして接続を閉じてから、ユーザーをインデックスページにリダイレクトします。

リクエストがGETリクエストの場合、つまりユーザーがページにアクセスしたばかりの場合は、create.htmlというテンプレートファイルをレンダリングします。

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

次に、create.htmlテンプレートファイルを開きます。

  1. nano templates/create.html

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

フラスコノート/テンプレート/作成.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Add a New Note {% endblock %}</h1>
    <form method="post">
    <div class="form-group">
        <label for="content">Note Content</label>
        <textarea type="text" name="content"
               placeholder="Note content, you can use Markdown syntax" class="form-control"
               value="{{ request.form['content'] }}" autofocus></textarea>
    </div>

    <div class="form-group">
        <button type="submit" class="btn btn-primary">Submit</button>
    </div>
    </form>

{% endblock %}

ここでは、メモの内容にテキスト領域のあるフォームを使用します。 request.formを使用して、フォームの送信で問題が発生した場合(たとえば、コンテンツが提供されなかった場合)に保存されているフォームデータにアクセスします。 ユーザーがPOSTリクエストでアプリケーションにデータを送信するために押すために、テキスト領域の下に送信ボタンを追加します。

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

次に、base.htmlファイルを開いて、New Noteボタンをナビゲーションバーに追加します。

  1. nano templates/base.html

次のように、強調表示されたコードでファイルを編集します。

フラスコノート/テンプレート/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')}}">FlaskNotes</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>

            <li class="nav-item active">
                <a class="nav-link" href="{{ url_for('create') }}">New Note</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>

    <!-- 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>

url_for()機能を使用して、ナビゲーションバーに新しい<li>アイテムを追加し、create()ビュー機能にリンクします。 これにより、ナビゲーションバーから新しいメモを作成するためのページにアクセスできます。

まだ実行していない場合は、開発サーバーを実行します。

  1. flask run

ブラウザを使用してhttp://127.0.0.1:5000/createに移動し、次のマークダウンメモを追加します。

### Flask
Flask is a **web** framework for _Python_.

Here is the Flask logo:

![Flask Logo](https://flask.palletsprojects.com/en/1.1.x/_images/flask-logo.png)

このマークダウンには、h3の見出し、太字のweb、斜体のPython、および画像が含まれています。

メモを送信すると、アプリケーションがそれをHTMLにフォーマットしていることがわかります。

Markdown Formatted Note

これで、ユーザーがデータベースに新しいメモを追加できる新しいルートができました。 ユーザーはMarkdown形式でメモを取ることができ、アプリケーションはインデックスページにHTMLでメモを表示します。

このリポジトリからアプリケーションの完全なコードにアクセスできます。

結論

マークダウン形式でメモを取るためのFlaskアプリケーションを作成しました。これにより、ユーザーは見出し、太字、斜体のテキストなどのテキスト形式を使用したり、画像やリンクを追加したりできます。 アプリケーションをSQLiteデータベースに接続して、データを保存および取得しました。 マークダウンテキストをHTML変換に組み込んで、メモがページに表示されるようにしました。 PythonでのMarkdownの使用の詳細については、Pythonを使用する方法-Markdownを使用してMarkdownテキストをHTMLに変換するを参照してください。

Flaskの詳細については、次のチュートリアルを確認してください。