公開日:5/30/2020
    シェア:

    (Python)FLASKでSQLiteを使う(公式チュートリアル)

     
    Pythonを利用したWEBサイト制作の手助けをしてくれるFLASKで。データベースの操作をやってみましょう。

    今回使うのはSQLite3という軽量版のデータベースソフト。Flaskの公式マニュアルにあるチュートリアルの内容を、できるだけ日本語とわかりやすさに重点をおいて進めていきます。

    FlaskでSQLを使う環境をする

    まずは、今回のプロジェクと用に新しい仮想環境を作っておきましょう、
    作り方はPython(パイソン)でWEBサイトをつくる(Flask編)の記事にまとめているので、参考にしながら進めていきましょう。
    例では、仮想環境の名前を「QuickStart」プロジェクトの名前を「flaskr」で作成しています。

    一緒に「DB Browser for SQLite」もインストールしておきましょう。Anacondaとは関係のないアプリですが、SQLiteのデータメース操作をエクセル感覚でできるすぐれものです。
    詳しい情報とダウンロードは、https://www.dbonline.jp/sqlite-db-browser/をご覧ください。

    Flaskの開発ができるAnacondaにはSQLiteの機能があるのですが、うまく動かないので、sqlite3をインストールします。

    「HOME」から「Qt Console」を開きます。


    続いて、コンソールにSQLite3のインストールコマンドを入力しましょう。
    conda install -c blaze sqlite3
    sqlite3のパッケージが読み込まれて自動的にインストールが始まって完了します。

    仮想環境とDB Browser for SQLiteの準備ができたら、必要なフォルダを準備します。

    Steo0:フォルダを準備する

    メインモジュールやデータベースやHTMLファイルをいれるフォルダを作成します。
    既に「flaskr」フォルダを作ったの、その中に「static」と「templates」のフォルダを作成します。


    step1:データベーススキーマ

    データメースをあまち使わない人にとっては「スキーマ」の意味もよくわからないと思います。スキーマについて解説しているサイトもありますが、今ひとつつかみにくい……。
    ここではデータベースを作成して、データを入れる箱を作ると認識しておけば大丈夫です。

    では、公式のサンプルにそってデータベースを作っていきますが、どんなデータベースを作るのかを下の表にまとめました。

     データベース名entries 
     名前型 備考 
     idintefer プライマリーキー 
     titlestring  
     name string 

    データベースでは、各データごとにIDが付与されます。その番号をプライマリーキーといって、この番号を元に様々なやり取りが行われます。

    それでは、このデータベースを作成する処理を書いていきましょう。
    flaskrフォルダの中に「schema.sql」というファイルを作成します。


    ファイルを作成したら次のコードを入れましょう。
    【コード01】
    drop table if exists entries;
    create table entries (
      id integer primary key autoincrement,
      title string not null,
      text string not null
    );
    これで、データベースが作成されます。

    Step2:セットアップ

    続いて、プログラムのメイン部分を作っていきます。まずは、SQLiteを使えるようにしていきます。ここでも公式のサンプルに沿って、段階的にコードを書いていきます。

    まず、flaskrフォルダ内に「flaskr.py」ファイルを作成します。


    それでは、この中にコードを入れていきます。最初は必要な機能を入れます。

    【コード02-1】
    #インポート
    import sqlite3
    from flask import Flask, request, session, g, redirect, url_for, abort, render_template, flash
    from contextlib import closing
    公式には「from contextlib import closing」の記述はありませんが、この後にエラーが発生するため、含めています。

    次に設定情報を書いておきます。
    【コード02-2】
    #設定情報
    DATABASE = 'flaskr.db'
    DEBUG = True
    SECRET_KEY = 'development key'
    USERNAME = 'admin'
    PASSWORD = 'default'

    続いて、アプリの初期化です。
    【コード02-3】
    #アプリの初期化
    app = Flask(__name__)
    app.config.from_object(__name__)
    このfrom_object()は、変数を読み込む処理です。【コード02-2】で指定した情報を主翼しています。
    本来であれば、コードに管理者のユーザー名とパスワードを入れることはありえないのですが、今回は”データべースの扱い方”なので深くは考えません。

    次は、いよいよデータベースに接続します。
    【コード02-4】
    #データベースに接続
    def connect_db():
        return sqlite3.connect(app.config['DATABASE'])
    ここまでできたら、最後に実行用のコードを入力します。
    【コード02-5】
    #実行用コード
    if __name__=='__main__':
        app.debug = True
        app.run()
    Spiderで実行しやすいように「app.debug = True」も追加しています。このコードは、全体の一番最後にあるようにしたいので、この後コードを追加する場合は、#実行用コードの上に入れるようにしましょう。

    公式ではここで実行してみましょうとありますが、これで実行しても何も表示されないので、さらに進みます。

    Step3:データベースを作成する

    step1でデータベースを作成しましたが、さらにFlaskで操作できるように設定をしてあげます。
    schema.sql に次のコードを追加しましょう。
    【コード02-6】
    sqlite3 flaskr.db < schema.sql
    from __future__ import with_statement
    from contextlib import closing

    データベースをFlaskから操作できるようにするコードとのこと。
    続いて、flaskar.pyに次のコードを追加します。
    【コード02-7】
    #schema.sqlに接続して実行
    def init_db():
        with closing(connect_db()) as db:
            with app.open_resource('schema.sql') as f:
                db.cursor().executescript(f.read())
            db.commit()

    Step4:データベースの利用

    続いて、データベースの処理の前後で動きを分けられるようにコードを追加します。
    【コード02-8】
    #データベースの処理分け
    @app.before_request
    def before_request():
        g.db = connect_db()
    @app.after_request
    def after_request(response):
        g.db.close()
        return response

    Step5:View関数

    ついにここのステップで表示ができるようにしていきます。ここではエントリーごとの処理を書いていきます。

    エントリーページ

    DB内のすべてのエントリ一覧ページを表示する処理
    【コード02-9】
    #エントリーのページ
    @app.route('/')
    def show_entries():
        cur = g.db.execute('select title, text from entries order by id desc')
        entries = [dict(title=row[0], text=row[1]) for row in cur.fetchall()]
        return render_template('show_entries.html', entries=entries)

    エントリーの追加

    ログイン時に新規エントリーを追加したときに表示する処理
    【コード02-10】
    #エントリーの追加
    @app.route('/add', methods=['POST'])
    def add_entry():
        if not session.get('logged_in'):
            abort(401)
        g.db.execute('insert into entries (title, text) values (?, ?)',
                     [request.form['title'], request.form['text']])
        g.db.commit()
        flash('New entry was successfully posted')
        return redirect(url_for('show_entries'))

    ログインとログアウト

    ユーザーのログインとログアウト時も表示する処理
    【コード02-11】
    #ログイン
    @app.route('/login', methods=['GET', 'POST'])
    def login():
        error = None
        if request.method == 'POST':
            if request.form['username'] != app.config['USERNAME']:
                error = 'Invalid username'
            elif request.form['password'] != app.config['PASSWORD']:
                error = 'Invalid password'
            else:
                session['logged_in'] = True
                flash('You were logged in')
                return redirect(url_for('show_entries'))
        return render_template('login.html', error=error)
    #ログアウト
    @app.route('/logout')
    def logout():
        session.pop('logged_in', None)
        flash('You were logged out')
        return redirect(url_for('show_entries'))

    Step6:テンプレート

    続いて、表示用のHTMLを作っていきます。設置するのはtemplatesフォルダの中に入れておきます。

    layout.html

    WEBページのヘッダー部分など共通する部分を書きます。
    【コード02-15】
    <!doctype html>
    <title>Flaskr</title>
    <link rel=stylesheet type=text/css href="{{ url_for('static', filename='style.css') }}">
    <div class=page>
      <h1>Flaskr</h1>
      <div class=metanav>
      {% if not session.logged_in %}
        <a href="{{ url_for('login') }}">log in</a>
      {% else %}
        <a href="{{ url_for('logout') }}">log out</a>
      {% endif %}
      </div>
      {% for message in get_flashed_messages() %}
        <div class=flash>{{ message }}</div>
      {% endfor %}
      {% block body %}{% endblock %}
    </div>

    show_entries.html

    ここで、新規エントリーに関連する部分です。
    【コード02-13】
    {% extends "layout.html" %}
    {% block body %}
      {% if session.logged_in %}
        <form action="{{ url_for('add_entry') }}" method=post class=add-entry>
          <dl>
            <dt>Title:
            <dd><input type=text size=30 name=title>
            <dt>Text:
            <dd><textarea name=text rows=5 cols=40></textarea>
            <dd><input type=submit value=Share>
          </dl>
        </form>
      {% endif %}
      <ul class=entries>
      {% for entry in entries %}
        <li><h2>{{ entry.title }}</h2>{{ entry.text|safe }}
      {% else %}
        <li><em>Unbelievable.  No entries here so far</em>
      {% endfor %}
      </ul>
    {% endblock %}

    login.html

    ログイン画面を表示する部分です。
    【コード02-14】
    {% extends "layout.html" %}
    {% block body %}
      <h2>Login</h2>
      {% if error %}<p class=error><strong>Error:</strong> {{ error }}{% endif %}
      <form action="{{ url_for('login') }}" method=post>
        <dl>
          <dt>Username:
          <dd><input type=text name=username>
          <dt>Password:
          <dd><input type=password name=password>
          <dd><input type=submit value=Login>
        </dl>
      </form>
    {% endblock %}

    Step7:スタイルを追加する

    WEBページを作成するときに必要不可欠な「スタイルシート」も設定しておきましょう。
    staticフォルダに「style.css」というファイルを作ってコードを書いていきます。
    【コード02-15】
    body            { font-family: sans-serif; background: #eee; }
    a, h1, h2       { color: #377BA8; }
    h1, h2          { font-family: 'Georgia', serif; margin: 0; }
    h1              { border-bottom: 2px solid #eee; }
    h2              { font-size: 1.2em; }
    .page           { margin: 2em auto; width: 35em; border: 5px solid #ccc;
                      padding: 0.8em; background: white; }
    .entries        { list-style: none; margin: 0; padding: 0; }
    .entries li     { margin: 0.8em 1.2em; }
    .entries li h2  { margin-left: -1em; }
    .add-entry      { font-size: 0.9em; border-bottom: 1px solid #ccc; }
    .add-entry dl   { font-weight: bold; }
    .metanav        { text-align: right; font-size: 0.8em; padding: 0.3em;
                      margin-bottom: 1em; background: #fafafa; }
    .flash          { background: #CEE5F5; padding: 0.5em;
                      border: 1px solid #AACBE2; }
    .error          { background: #F0D6D6; padding: 0.5em; }

    テストとトラブルシューティング
    コードが完成したら実行をして下のアドレスにアクセスをしてみましょう。


    ログイン画面が表示されれば成功ですが、エラー画面になることがあります。

    エラー内容が「sqlite3.OperationalError: no such table:○○~~」の場合、データベースは作れたんですが、テーブルが作れないというエラーになります。


    こうなったら、一度データベースの中身を確認したいので、コンソールを右クリックして、「終了」をクリックして止めます。


    続いて、「DB Browser for SQLite」を開いて「データベースを開く」をクリックして、今回のプログラムのフォルダを探します。
    その中に「flaskr.db」のファイルがあれば、選択して開きます。


    データベースが開きました。やはりStep1のコードでデータベースのファイルは作られているみたいですが、テーブルが0担っているので、中身が作られていません。


    せっかくデータベースを開いているんlで、ここでテーブルを作ってしまいましょう。
    「テーブルを作成」をクリックするとテーブル作成画面が表示されます。

    最初は、テーブル名にentriesと入力します。


    続いて、追加をクリックしてフィールドを作ります。各フィールドは下の図を参考に設定をしましょう。


    入力が終わったら、右下の「OK」をクリックします。
    テーブルの作成が終わったので、「ファイル」→「変更を書き込み」をクリックします。
    ※「変更を書き込み」をクリックしないと、データベースが更新されないためエラーになります。

    変更の書き込みが終わったら、再度、テストを開きます、


    ログイン画面が表示されれば成功です、


    では、動作確認をしてみましょう。右上の「log in」をクリックします。


    UsernameとPasswordを入力します。これはコードで書きましたね。

     Usernameadmin
     Passworddefault

    入力が終わったら「Login」ボタンをクリックします。


    投稿が表示されました、タイトルとテキストを適当に入力して「Share」をクリックしてみましょう。


    下に入力した内容が表示されました、同じことを繰り返すと、上に追加されていきます。


    では、画面右上の「log out」をクリックしてみましょう。


    最初の画面に戻りますが、投稿した内容も残っています。

    一応、データベースも確認すると、

    データがしっかり追加されていることが確認できます。

    今回も、公式のチュートリアルだけではスムーズに進みませんでしたが、エラーページを翻訳して読めばなんとかなるレベルでした。

    本来であれば。ここに削除機能など実装しないといけないのですが、そこまでは公式のチュートリアルには載せられていないので、一旦、ここで完了とします。