ページ

2010年10月5日

MongoDBで作る20分ブログ

20分かどうかはよく分かりませんが、とりあえず、MongoDBを使ってエントリの登録、表示、編集するだけのブログのサンプルです。WebのフレームワークはFlaskを使っています。それ以外は特別なものはないはずです。コメントの追加は、気が向いたらやります。

まず、MongoDBをPythonから利用するにはpymongoを使いますが、これはMongoDBに対する薄いラッパーです。ORマッパーっぽいというか、MongoDBは全く構造化されていないのでもう少し構造化する者というか、堅いRDBから抜け出して生ぬるいMongoDBに来たのにまた、もうちょっと堅くなろうとするのか、まあそのようなライブラリがいくつかあります。

今回はFlaskを使っていますが、Django好きには、Django-MongoKitというのがいるらしいです。でも、僕はあんまりDjangoを使わないので、おしまい。で、Django-MongoKitというのは、MongoKitをDjangoから使う者です。MongoKitとは、
MongoKit framework try to keep its simplicity when you manage mongodb in python. MongoKit was developed to be fast and light with KISS and DRY in mind. MongoKit brings structured schema and validation layer on top of the great pymongo driver
ということです。構造化したスキーマやバリデーションなどもう少し高レベルのAPIを提供しようというものです。

それ以外には、MongoEngineという人もいるらしいです。基本的にはMongoKitと同じ思想です。MongoEngineのサイトにはMongoEngineはDocument-Object Mapperと書いています。なかなか面白い表記です。

高レベルなAPIもありますが、やっぱり今回はpymongoを直接扱います。

import pymongo
from pymongo.objectid import ObjectId
from flask import Flask, request, flash, render_template, url_for
from flask import session, redirect
from flask import g

def req_start():
    g.mongo = pymongo.Connection()

def req_end(response):
g.mongo.disconnect()
    del g.mongo
    return response

app = Flask(__name__)
app.debug = True
app.before_request(req_start)
app.after_request(req_end)

とりあえず、リクエストが来たらグローバルな値にMongoDBへのコネクションをセットして、リクエストが終わるとMongoDBとの接続を切って変な状態が残らないようにしています。

@app.route("/")
@app.route("/")
def index(oid = None):
    db = g.mongo.blog
    if oid:
        entries = db.entry.find({"_id": ObjectId(oid)})
    else:
        entries = db.entry.find().sort([("created", -1)])

    return render_template("index.html", entries=entries)

一覧とエントリの詳細を表示しています。サボっていますが、許してください。oidが指定されていたらMongoDBの内部IDで検索して、それらを表示します。oidが指定されていなければ、全部取得して日付でソートしています。

@app.route("/save", methods=["POST"])
def save():
    db = g.mongo.blog
    form = request.form
    oid = form.get("oid", None)
    if not oid:
        entry = {}
    else:
        entry = db.entry.find_one({"_id": ObjectId(oid)})
       
    entry["title"] = form["title"]
    entry["body"] = form["body"]
    result = db.entry.save(entry)
    oid = str(result)

    return redirect(url_for("index", oid=oid))

保存も、特に変なところはないですね。バリデーションをサボっているのはご愛敬。データはtitleとbodyしかありません。

テンプレートの中身はgithubのコードをみてください。
で、ここまでがきっと20分です。

コメントは、Embedded Documentにすればあんまり考えずにできます。でも、その場合だとサイドバーをつけたときに、「最近のコメント」を表示できないです。db.commentというテーブルを作って、コメントを2段階で取得した方がいいです。でも、でも、でも。

でわでわ。

0 件のコメント: