「Pythonでwebサービスを作る」学習メモ2巻②
こんにちは。きゃにすたーです。
この記事は「Pythonでwebサービスを作る」の2巻の学習メモその②です。
前回の記事はこちら。
ソースはこちらに。
データベース(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)
PythonとPostgreSQLの連携
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)とは、オブジェクト指向における「オブジェクト」とリレーショナルデータベースをマッピングする(関連付ける)ことです。
ごちゃごちゃいう前にやってみましょう。詳しい説明は以下リンクをご覧ください。
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__
を追加したのと、id
にauto_increment=True
を追加しています。
書いてある通りに進めると、idというカラムを持つテーブルを作っていないのでそのまま動かすとエラーになります。(なりました)
テーブルをちゃんと作ってあげて、クラス定義だけちゃんとやってなんやかんや後は本に書いてある通り進めると、以下のような感じになります。 ちゃんと出てくれました。
DBにもちゃんとデータが入っているのが確認できます。
マイグレーション
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巻が終わり次第やってみたいと思います。ありがとうございました。