見出し画像

Flask Web Development P42~63

データベース
Pythonで使えるデータベースにはMySQL、Postgres、SQLite、Redis、MongoDB、CouchDBなどなどありますが、ここでSQLAlchemyを利用します。

んじゃインストールということで

> conda install -c conda-forge flask-sqlalchemy

SQLAlchemy様々なデータベースに対して(URLを利用して)接続してSQLを実行することができます。

Database engine URL

・MySQL mysql://username:password@hostname/database
・Postgres postgresql://username:password@hostname/database
・SQLite (Unix) sqlite:////absolute/path/to/database
・SQLite (Windows) sqlite:///c:/absolute/path/to/database

SQLALCHEMY_DATABASE_URI'で接続するデータベース情報をURL形式で入力しています。
・username: データベースにアクセスできるユーザー
・password:データベースにアクセスするときのパスワード
・localhost:デスクトップで作業しているので、とりあえずlocalhostです。本番機はまた異なるhostが入ります。
・database:使用するデータベース名です。

SQLALCHEMY_COMMIT_ON_TEARDOWN':データベース変更時に自動コミットする設定

SQLに関してはphpとsqlの本などを読むと参考になると思います。

app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = Falseについてはエラーが出ないようにFalseを入れています。
Flask-SQLAlchemyには、SQLAlchemyの上に階層化される独自のイベント通知システムがあります。これを行うために、SQLAlchemyセッションへの変更を追跡します。これには余分なリソースが必要になるため、オプションSQLALCHEMY_TRACK_MODIFICATIONSを使用すると、変更追跡システムを無効にできます。現在、オプションのデフォルトはTrueですが、将来、そのデフォルトはFalseに変更され、イベントシステムが無効になります。
とか書いてあったけどむつかしい...。

テーブル構成

データベースのテーブル構成を管理するクラスを作ります。
hello.pyにはこんな感じのコードを追加します。

class Role(db.Model):
   __tablename__ = 'roles'
   id = db.Column(db.Integer, primary_key=True)
   name = db.Columnn(db.String(64), unique=True)
  users = db.relationship('User', backref='role')
   
   def __repr__(self):
       return '<Role %r>' % self.name  
   
class User(db.Model):
   __tablename__ = 'users'
   id = db.Column(db.Integer, primary_key=True)
   username = db.Column(db.String(64), unique=True, index=True)
   role_id = db.Column(db.Integer, db.ForeignKey('role.id'))

   def __repr__(self):
       return '<User %r>' % self.username

__tablename__: データベース内のテーブルの名前を定義します。

・db.Columnでどんな入力ルールを設定するかを決めています。
・db.Integerは可変長文字列です。
・primary_key:テーブルに格納されているデータをに格納されているデータを識別するための目印のようなものです。
・__repr__()メソッドはデバッグやテストのために使用できる読みやすい文字列表現を与えるために使用しています。
・uerとroleの間にdb.relationshipやbackrefで関連付けています。
・db.ForeignKey('role.id')では行のid値を持つ列として解釈されることを指定します。

ここでは1体多、多対一の関連性を説明しており、
many-to-manyの関係は12章で紹介されるらしい。

MySQLにデータベースをターミナル上で作りましょう。
その後、db.create_all()を実行してテーブルを作りましょう。

ここでgrant all privilagesがうまく動かなかったのは謎...。
本番機で影響ないことを祈る。

あとはターミナル上で
RoleとUserの設定をして、

>>> from hello import Role, User
>>> admin_role = Role(name='Admin')
>>> mod_role = Role(name='Moderator')
>>> user_role = Role(name='User')
>>> user_john = User(username='john', role=admin_role)
>>> user_susan = User(username='susan', role=user_role)
>>> user_david = User(username='david', role=user_role)

session.addで設定をデータベースに加えるコマンドを入力して

>>> db.session.add_all([admin_role, mod_role, user_role,
... user_john, user_susan, user_david])

データベースに入力する

>>> db.session.commit()

そうするとデータベースにRoleとUserのデータを入力できました。

Webページからデータベースに変更を加える

まずは、SECRET_KEYを設定します。

import os
SECRET_KEY = os.urandom(32)
app.config['SECRET_KEY'] = SECRET_KEY

SECRET_KEYを設定しないと、RuntimeError: A secret key is required to use CSRF. Traceback (most recent call last)が出力されます。

hello.pyのindexを以下のように変更しましょう。

@app.route('/', methods=['GET', 'POST'])
def index():
    form = NameForm()
    if form.validate_on_submit():
        user = User.query.filter_by(username=form.name.data).first()
        if user is None:
            user = User(username = form.name.data)
            db.session.add(user)
            session['known'] = False
        else:
            session['known'] = True
        session['name'] = form.name.data
        form.name.data = ''
        return redirect(url_for('index'))
    return render_template('index.html', form = form, 
                             name = session.get('name'),
                            known = session.get('known', False))

index.htmlを以下のように更新します。

{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}Flasky{% endblock %}
{% block page_content %}
<div class="page-header">
<h1>Hello, {% if name %}{{ name }}{% else %}Stranger{% endif %}!</h1>
{% if not known %}
<p>Pleased to meet you!</p>
{% else %}
<p>Happy to see you again!</p>
{% endif %}
</div>
{{ wtf.quick_form(form) }}
{% endblock %}

やったー!うまい具合に動いた~。


この記事が気に入ったらサポートをしてみませんか?