#floatcontents
 * Macaron: O/R Mapper [#sbb1a551]
 #ref(macaron_logo.png,nolink,around,right)
 ~MacaronはPythonで書かれたSQLite用のO/Rマッパー(Object-Relational Mapper;ORM)です。
 ~軽量WebフレームワークであるBottleを使ってアプリケーションを作ろうと思ったのですが、簡単、軽量なORMが見つからず、「作ってしまえ!」と思い立ち、どぶおが作成、公開しているものです。MacaronもBottleもモジュール本体はそれぞれ1つのファイルですので、合わせて2つのファイルでフルスタックWebフレームワーク(MacaronでORM、Bottleでルーティングおよびテンプレート)が実現できるはずです(たぶん)。
 ~なお、ドキュメント等は(怪しげな)英語で作成しているため、日本語での解説ページを作成しておきます。アルファ版という位置づけなのでバグ等発見されましたらコメント戴けると助かります⌣。
 ~このMacaronが気軽な開発の一助となれば幸いです。
 
 ** 関連ページ [#i6688feb]
 - アーカイブおよびソースの取得
 -- Python Package Index (PyPI) -- http://pypi.python.org/pypi/macaron
 -- GitHub -- https://github.com/nobrin/macaron
 - ドキュメント
 -- Macaron documentation(英語) -- http://nobrin.github.com/macaron/
 
 - 軽量Webフレームワーク Bottle -- http://bottlepy.org/
 
 ** 特徴 [#h03e2623]
 Macaronは軽量アプリケーション開発においてSQLiteを簡単に使用できるようにするために開発されています。
 
 - SQLite対応のO/Rマッパーです
 - Python標準ライブラリ以外には依存していません
 - データベースのテーブル情報からモデルのフィールドを自動定義します(ある程度)
 - 多対一リレーションに対応しています
 - あらかじめ定義された検証機構を持ち、ユーザーで定義することも可能です
 - 軽量WebフレームワークBottleのプラグインを標準で使用可能です
 - モジュール本体は1つのファイルで構成されています
 
 以上のような特徴を備えています。元々はお手軽な開発の際に用いることを目指したライブラリなのであまり凝ったことをするよりも簡単に使えるものを目指しています。また、最近Djangoを使った開発を行っているため、DjangoのO/Rマッパーの影響を受けています。~
 最近、メンテナンスを再開したのでGithubに最新版(プレリリースだけど)をコミットしてあります。
 最近、メンテナンスを再開したのでGithubに最新版(プレリリースだけど)をコミットしてあります。0.4.0からは多対多サポートが追加されています。
 
 ** インストール方法 [#lf4852ce]
 インストールはPyPIまたはGitHubからソースアーカイブを取得するかeasy_installでインストールします。
 
 *** アーカイブから [#j75dfaaf]
  % tar zxvf macaron-0.3.0.tar.gz
  % cd macaron
  # python setup.py install
 
 *** easy_install [#w37c3ec5]
  # easy_install macaron
 
 * チュートリアル [#v4cec8c0]
 ** 使用例 [#u77807b8]
 例えば以下のようなコードが書けます。
 
  >>> import macaron
  >>> macaron.macaronage("members.db")
  >>> team = Team.create(name="Houkago Tea Time")
  >>> team.members.append(name="Azusa", part="Gt2")
  <Member object 1>
  >>> macaron.bake()
  >>> azu = Member.get("part=?", ["Gt2"])
  >>> print azu
  <Member 'Azusa : Gt2'>
  >>> macaron.db_close()
 
 実際に使用するときはモデルクラスの定義が必要になりますが、最小限の場合、以下のようにクラス名の定義のみで使用可能です。
 
  class Team(macaron.Model): pass
 
 この場合、データベーステーブルの情報よりフィールド情報などを自動的に定義します。
 
 ** テーブルの準備 [#q5664526]
 ~シンプルなモジュールのため、MacaronはCREATE SQLの発行メソッドがありません。テーブルの作成は手動で行って下さい。Macaronはexecuteメソッドをラップしているので、executeメソッドでSQLを実行することも可能です。
 ~このチュートリアルで使用するテーブルは以下の通りです。
 
 :teamテーブル -- memberが所属するteamを格納する|
  CREATE TABLE team (
      id      INTEGER PRIMARY KEY,
      name    VARCHAR(20)
  );
 
 :memberテーブル|
  CREATE TABLE member (
      id          INTEGER PRIMARY KEY,
      table_id    INTEGER REFERENCES team (id) ON DELETE CASCADE,
      first_name  VARCHAR(20),
      last_name   VARCHAR(20),
      part        VARCHAR(10),
      age         INT
  );
 
 この例ではmemberテーブルとteamテーブルは多対一の関係にあります。
 
 ** モデルの定義 [#vf36a7ca]
 ~Macaronでデータベースのテーブルにアクセスするにはモデルクラスを定義する必要がありますが、テーブル情報からある程度は自動生成されます。クラスを定義するにはmacaron.Modelを継承します。
  class Team(macaron.Model): pass
  
  class Member(macaron.Model):
      team = macaron.ManyToOne(Team, related_name="members")
      age = macaron.IntegerField(max=18, min=15)
 以上のように定義します。
 
 *** テーブル名 [#q330b1e1]
 クラスとテーブル名の対応は自動で行われます。(今のところ)クラス名を小文字にしたものがテーブル名になります。Teamならteam、Memberならmemberです。別の名前を使いたい場合は、クラスプロパティとして''_table_name''を指定します。
 
  class MyTable(macaron.Model):
      _table_name = "my_bookmarks"
 
 *** 多対一関連の定義 [#h2a83415]
 多対一のリレーションは自動で認識されませんので多から一に向けてリレーションを指定します。上の例ではMemberのteamプロパティがそれに当たります。このとき、TeamからMemberがrelated_nameパラメータで指定された名前でリレーションが張られます。省略した場合は''テーブル名_set''が指定されます。外部キー(fkey)および関連先テーブルのID(id)は以下のように指定できます。
  class Member(macaron.Model):
      belongs_to = macaron.ManyToOne(Team, fkey="team_id", key="id", related_name="members")
 
 *** フィールドの定義 [#gc321960]
 上の例ではVARCHAR型は、macaron.CharFieldとして認識され、VARCHAR(20)により文字列の最大長(max_length)が制限としてセットされます。フィールドのデータ型は自動認識され、SQLiteの規則に従って以下のように決定されます。大文字小文字は区別されません。
 - macaron.FloatField -- データ型名にREAL, FLOA, DOUBの文字が含まれている(例:FLOAT, DOUBLE)
 - macaron.IntegerField -- データ型名にINTが含まれている(例:INTEGER,INT)
 - macaron.CharField -- データ型名にCHAR, CLOB, TEXTが含まれている
 
 その他、日付型を認識します。
 - macaron.TimestampField -- TIMESTAMPまたはDATETIME
 - macaron.DateField -- DATE
 - macaron.TimeField -- TIME
 
 このように、自動認識されますが、この例のageには上限下限を設定したかったので、
  age = macaron.IntegerField(max=18, max=15)
 というように指定します。現時点ではCHECK制約の自動認識は行いません。
 
 ** 一般的な使用方法 [#r6d36f53]
 Macaronを初期化した後、使用可能になります。
 
  import macaron
  # 初期化
  macaron.macaronage("members.db")
  # データ操作
  team = Team.get("name=?", ["Houkago Tea Time"])
  team.members.append(first_name="Azusa", last_name="Nakano", part="Gt2", age=16)
  for m in team.members.all():
      print m
  # コミット
  macaron.bake()
 
 ** Bottleでの使用方法 [#k66e6d22]
 軽量の小型WebフレームワークBottleのプラグインMacaronPluginが標準で使用できます。
 
  #!/usr/bin/env python
  from bottle import *
  import macaron
  
  # install MacaronPlugin instance
  DB_FILE = "bookmark.db"
  install(macaron.MacaronPlugin(DB_FILE))
  
  # Class definition
  class Bookmark(macaron.Model): pass
  
  # Route definition
  @route("/hello")
  def index():
      html = "<html>\n<head><title>My Bookmarks</title></head>\n"
      html += "<body>\n<h1>My Bookmarks</h1>\n<ul>\n"
      for bookmark in Bookmark.all():
          html += '<li><a href="%s">%s</a></li>\n' % (bookmark.url, bookmark.title)
      html += "</ul>\n</body>\n</html>\n"
      return html
  
  if __name__ == "__main__":
      run(host="0.0.0.0", port=8080)
 
 動作サンプルはソースツリーの''examples/bottle''以下にあります。
 
 ** コメント [#y30afa68]
 - 利用させて頂いています。ありがとうございます。 -- piss &new{2014-07-09 (水) 11:07:51};
 - macaron.cleanup()において、connectを開放する為に「macaron._m.connection["default"].close()」を追記した方がよいのではないでしょうか?ご検討ください。 -- piss &new{2014-07-09 (水) 11:08:16};
 -- コメントありがとうございます。しばらく開発停止してましたが、最近また再開しましたので検討してみます。 -- どぶお &new{2014-07-10 (木) 08:07:20};
 - お世話になっております。_generate_sqlにおいて[LIMIT]=>[OFFSET]の順番で指定しないとエラーになうようです。 -- piss &new{2014-07-16 (水) 16:42:31};
 
 #comment