2歩戻ったら2.5歩進みたい

関東で働くweb developerのブログ

「Pythonでwebサービスを作る」学習メモ2巻②

こんにちは。きゃにすたーです。

この記事は「Pythonwebサービスを作る」の2巻の学習メモその②です。

前回の記事はこちら。

canisterism.hatenablog.com

ソースはこちらに。

github.com

データベース(PostgreSQL)

本書ではデータベースとしてPostgreSQLを使います。

brewでインストールします。

$ brew install postgresql

インストールが終わったら、PostgreSQLを起動させます。

$ postgres -D /usr/local/var/postgres
>>2018-05-01 23:19:11.015 JST [1117] LOG:  listening on IPv6 address "::1", port 5432
>>2018-05-01 23:19:11.015 JST [1117] LOG:  listening on IPv4 address "127.0.0.1", port 5432
>>2018-05-01 23:19:11.016 JST [1117] LOG:  listening on Unix socket "/tmp/.s.PGSQL.5432"
>>2018-05-01 23:19:11.050 JST [1118] LOG:  database system was shut down at 2018-05-01 23:14:16 JST
>>2018-05-01 23:19:11.058 JST [1117] LOG:  database system is ready to accept connections

無事起動できました。

まず、DBを作ります。

$ createdb flasknote

特になんの反応もなければ作れています。

このままだと、全く何の情報も持っていないので、まず作ったDBに接続します。

$ psql flasknote
psql (10.3)
Type "help" for help.

flasknote=#

これを入力すると入力待ちの状態になります。これでSQLを発行することができます。

テーブル作成

$ CREATE TABLE messages ( username varchar(48),
                        message varchar(140)
                        );
CREATE TABLE

レコードの追加

$ INSERT messages VALUES ( 'testuser',''testmessage');
INSERT 0 1

レコード抽出

$ SELECT username, messages FROM messages
 username |   message
----------+-------------
 testname | testmessage
(1 row)

PythonPostgreSQLの連携

pythonからPostgreSQLにアクセスするには、psycopg2というライブラリを使用します。

このライブラリを使う時は、dbが起動されている状態であることが前提となります。

conn = psycopg2.connect("dbname=flasknote") #dbと接続する
cur = conn.cur #カーソルの取り出し
cur.execute("SELECT * FROM messages") #SQLの発行
cur.fetchone() #抽出したレコードを1行取り出す
>>> ('testname','testmessage')

ORM

ORM(Object Relational Mapping)とは、オブジェクト指向における「オブジェクト」とリレーショナルデータベースをマッピングする(関連付ける)ことです。

ごちゃごちゃいう前にやってみましょう。詳しい説明は以下リンクをご覧ください。

www.atmarkit.co.jp

ORMはSQLAlchemyを使います。今回はFlaskに特化したFlask-SQLAlchemyを使いますので、これとPostgreSQLのためのpsycopg2をpipします。

$ pip3 install flask-sqlalchemy
$ pip3 install psycopg2 psycopg2-binary

他にも書かなければいけないスクリプトがなんやかんやとあるんですが、詳細は買って見てください。ちょっとハマったところだけメモしたいと思います。

7.4 モデルを作成する

この章ですが、ここまでに作ったDBとは別のDBでサンプルを動かしているので気をつけてください。僕の方で見落としや見間違いをしているのかもしれませんが、とりあえず僕はハマりました(所要時間3時間)。

ここまでに作ったのはflasknoteというDBと、messageという名前のテーブルですが、7.4からはまた別のテーブルを使います。とりあえずappdb01というテーブルを作ります。

CREATE TABLE appdb01 (id serial,username varchar(48),description varchar(140),user_image_url varchar(140));

1つ目のカラムはidという名前でシーケンス属性です。つまりレコードを挿入するたびに値が1つづつ増えていきます。

そして肝心のクラス定義ですが、こんな感じで書きました。

class User(db.Model):
    __tablename__="appdb01"
    id = db.Column(db.Integer,primary_key=True,autoincrement=True) 
    username = db.Column(db.String(64), index=True,unique=True)
    description = db.Column(db.String(120), index=True,unique=True)
    user_image_url = db.Column(db.String(120), index=True,unique=True)

ここのスクリプトはほぼ本の通りに書いていますが、__tablename__を追加したのと、idauto_increment=Trueを追加しています。

書いてある通りに進めると、idというカラムを持つテーブルを作っていないのでそのまま動かすとエラーになります。(なりました)

テーブルをちゃんと作ってあげて、クラス定義だけちゃんとやってなんやかんや後は本に書いてある通り進めると、以下のような感じになります。 f:id:canisterism:20180503153619p:plain ちゃんと出てくれました。

DBにもちゃんとデータが入っているのが確認できます。 f:id:canisterism:20180503153718p:plain

マイグレーション

DBの設定やら立ち上げやらそれらに使ったSQLやらなんやらをまとめること…みたいな認識ですが、大体合ってると信じたい。flaskにはマイグレーション専用のモジュールがありますので使っていきましょう。

まずpipします。

$ pip3 install flask_migrate

そして、app.pyで以下のように書きます。

from flask_migrate import Migrate

app = Flask(__name__)
db = SQLAlchemy(app)
migrate = Migrate(app,db)

Migrateモジュールをインポートして、appとdbをセットします。

最後に、ORMに基づいてデータベースのテーブルを初期化します。

$ flask db init
$ flask db migrate

これより後は、データベースの構造を変更するたびにflask db updateします。

まとめ

2巻の内容は以上です。前半でBootstrapを使って見た目を整え、後半ではDBと接続するという内容でした。初めて自分でwebの実装をしたので楽しかった反面、本に書いていないエラーに当たった時がなかなかしんどかったです。ただ、実際に手を動かしながら格闘できたのは良い経験になりました。特にORMは「プロになるためのweb技術入門」であまり理解できなかったのですが、ちゃんと手を動かすことでちょっとわかった気になれました。

まぁコードを書いてみるとなんのことはなく、ただDBと入力される値を紐付けてるだけやんけという感じですね。ですが、仮にデータベースとオブジェクトの紐付けがなかった場合を考えると、今回のような入力値を受け取ってDBに保存したい時は、いちいちオブジェクトから値を取り出してSQLを組み立ててexecuteしなければなりません。

これは再現性及び安全性の面から言ってあまりよろしくなく、再現性という意味ではDBの構造を無視したSQLが発行されてエラーを吐く可能性があり、安全性という意味では生のSQLを組み立てることはSQLインジェクションなどセキュリティ上のリスクにDBを晒すことになります。

大体こんな感じの理解です。まだまだ分からんことだらけですが、ガッと3巻までやっていきたいと思います。

ところでこの2巻をやってる時に気づいたんですが、このシリーズは書いてある通りに進めれば質問箱のようなサービスが作れるわけではなく、あれぐらいのアプリを実装するための技術を一通り紹介する、という感じなんですね。

完全に最後には質問箱が出来上がると思い込んでいました。笑 ともあれ、自分で実装した方が力が付きますし3巻が終わり次第やってみたいと思います。ありがとうございました。