.. meta:: :keywords: web2py, framework, DAL, データベース抽象化レイヤ, DAL class, DALクラス .. module:: dal .. _class_dal: DAL === DALクラスのインスタンス生成よって、データベースへの接続が可能になります。この他に、テーブル定義・ トランザクション制御・テーブルデータのエクスポート・インポート・SQL文の実行などの機能をメソッドで提供しています。 参考: `Dependencies `_ | `依存関係 `_ .. include:: class_diagrams/dal.html インスタンス化 -------------- DALインスタンスの生成は、DALクラスのコンストラクタを使用します。またDALインスタンス名は、デフォルトでは **db** で設定されています [#f1]_ 。 .. topic:: 【 DALインスタンスの生成とアクセス 】 * 生成・・・・・・ **コンストラクタ** を使用します。 * アクセス・・・デフォルトのインスタンス名は **db** です。 .. class:: DAL() -> DALインスタンス コンストラクタはデータベースへの接続処理をします。 :: >>> db = DAL('sqlite://storage.db') :param uri: 接続文字列 :param pool_size: 接続プール :param db_codec: データベースのエンコード文字列 :param check_reserved: 予約語チェック :param migrate: マイグレーション :param fake_migrate: テーブル定義の再構築 :param migrate_enabled: マイグレーションが可能かどうかの設定 :param fake_migrate_all: 全テーブルで定義の再構築 :param attempts: 接続失敗時の再試行数 :param bigint_id: ``big-id`` , ``big-reference`` の使用 :param lazy_tables: テーブル定義の遅延実行 :param do_connect: データベースへの接続をするかどうか :return: DALインスタンス uri 接続文字列については :ref:`connection_string` を参照ください。デフォルト値は 'sqlite://dummy.db' です。 複数のデータベースへの接続試行 接続文字列にリスト形式で複数の接続先を記述すると、コンストラクタは順番に接続を試みます。 これは負荷分散目的でデータベースの複製がある場合に利用可能です。 :: >>> db = DAL(['接続文字列1', '接続文字列2', '接続文字列3', ]) 接続文字列1、接続文字列2、接続文字列3 と順番に接続を試していきます。 pool_size データベース接続でのコネクション数を設定します。デフォルト値は0です。0場合は接続プールは使用しません。 GAE及びSQLiteではこの設定は無視されます。 参考: `Connection Pooling `_ | `接続プール `_ db_codec データベースのエンコディングの設定です。デフォルトはUTF-8です。 check_reserved データベースの予約語が使われているか、チェックを行うかどうかの設定です。デフォルト値はNoneです。 詳細は参考サイトを参照ください。 参考: `Reserved Keywords `_ | `予約されたキーワード `_ migrate マイグレーションの設定をします。マイグレーションとはモデル(テーブル)定義が変更になった場合、 自動でデータベース上のテーブルも変更する動作のことです。 デフォルト値はTrueです。モデル定義が変更になった場合に、データベース上のテーブルも変更します。 データが格納されたテーブルのマイグレーションをどうするかなど、考慮すべき点はたくさんあります。詳細は参考サイトを参照ください。 参考: `Migrations `_ | `マイグレーション `_ migrate_enabled 接続時に全てのマイグレーションを有効・無効に指定できます。 デフォルトは *True* です。 *False* を指定した場合、全てのマイグレーションが無効になります。 複数のアプリケーションがデータベースを共有する場合、一つを除いてマイグレーションを無効にすることが推奨されているので、そのような状況下で使用します。 fake_migrate マイグレーションの失敗で、モデル定義とデータベーステーブルが不整合になったのを再構築します。 :meth:`dal.DAL.define_table` メソッドのパラメータとの違いは、define_table はテーブル単位ですが、こちらは全テーブルのマイグレーション問題の 修復をを試みます。しかしこのパラメータの機能では、失敗した場合の原因の究明は難しいです。 デフォルト値はFalseです。再構築する場合はTrueにし、migrateをFalseにします。 再構築完了したらFalseに戻します。詳細は参考サイトを参照ください。 参考: `Fixing Broken Migrations `_ | `壊れたマイグレーションの修復 `_ attempts 接続失敗時の再試行数の設定です。デフォルトは5です。 参考: `Connection Failures `_ | `接続の失敗 `_ bigint_id ``id`` 及び ``reference`` フィールドタイプをそれぞれ ``big-id`` と ``big-reference`` にする場合、Trueで指定します。 デフォルトは False です。 lazy_tables テーブル定義 :meth:`~DAL.define_table` の実行を遅延させます。 モデルで定義したテーブル中で不使用のものがある場合に、このパラメータを指定すると実行速度が上がります。 デフォルトはFalseです。 do_connect データベースの接続を実際にするかどうかを設定します。デフォルト値はTrueです。 もしFalseを指定した場合、データベースには接続されません。 その場合はアプリケーションは動作しますが、例えば、次のメソッドを使用することはできません。 :meth:`~Set.select` 、:meth:`~Table.insert` 、:meth:`~Set.update` 、:meth:`~Set.delete` SQL文を生成するだけの次のメソッドは使用可能です。 :meth:`~Set._select` 、 :meth:`~Table._insert` 、:meth:`~Set._update` 、:meth:`~Set._delete` メソッド -------- .. method:: DAL.define_table(tablename, *fields [, **args]) -> Tableインスタンス テーブルの定義をします。 :: db.define_table('person', Field('name'), format='%(name)s') tablename テーブル名を文字列で設定します。 \*fields フィールド定義は複数の設定が可能です。定義ではFieldクラスを使用します。 定義方法は :class:`~Field` を参照ください。 \*\*args オプションを指定します。複数のオプションを指定可能です。設定可能なオプションは次の通りです。 * format レコードの表示方法を指定します。 formatオプションの動作は :ref:`format` で説明します。 設定は、「文字列フォーマット操作」形式もしくは無名関数(lambda)で指定します。 * 文字列フォーマット操作 :: format='%(name)s' 変数はRowインスタンスになります。つまり内部では次のように変換されます。 :: '%(name)s' % Rowインスタンス 参考: `Python ライブラリリファレンス - 文字列フォーマット操作 `_ * 無名関数 :: format=lambda x: x.name or 'anonymous' 参考: `Record Representation `_ | `レコードの表現 `_ * migrate マイグレーションログを保存するファイルの名を指定します(省略可能)。 指定したファイル名はアプリケーションの database フォルダに生成されるファイル名になります。 デフォルトは *True* です。Trueだとweb2pyの接続文字列のハッシュ値からファイル名を生成します。 *False* を指定した場合、定義したテーブルのマイグレーションは行われません。 この他、詳細は参考サイトを参照ください。 参考: `Migrations `_ | `マイグレーション `_ * fake_migrate マイグレーションの失敗で、モデル定義とデータベーステーブルが不整合になったのを再構築します。 デフォルト値はFalseです。再構築する場合はTrueにし、migrateをFalseにします。 再構築完了したらFalseに戻します。詳細は参考サイトを参照ください。 参考: `Fixing Broken Migrations `_ | `壊れたマイグレーションの修復 `_ * primarykey レガシテーブルの利用時に、複数フィールドでキーを設定する場合に使用します。 設定するフィールドをリスト形式で指定します。 :: primarykey=['ivtype','ivno'] 指定しなくてもリストで指定したフィールドは、NOT NULL をセットします。 primarykey は今のところ、DB2、MS-SQL、Ingres、Informix のみ指定できます。 primarykeyの設定では :ref:`legacy_db` も参照ください。 * common_filter :ref:`common_filter` を設定します。 * この他、次のオプションも設定可能です。 singular , plural , trigger_name , sequence_name , polymodel , table_class 戻り値 戻り値はTableインスタンスが返ってきます。しかしこれは定義した時点で db.tablenameに関連付けられるため、捉える必要性はありません。 テーブル設定に関しては :ref:`legacy_db` と :ref:`table_inheritance` も参照ください。 参考: `DAL, Table, Field `_ | `DAL Table Field(日本語) `_ .. method:: DAL.commit トランザクション制御のコミット処理を行います。 :: >>> db.commit() web2py のモデル・ビュー・コントロール のコードは、web2pyによって制御コードが付加されます。 このため、より細かな制御を望まない限り、コミット・ロールバックを記述する必要はありません。 参考: `commit and rollback `_ | `コミットとロールバック `_ .. method:: DAL.rollback トランザクション制御のロールバック処理を行います。 :: >>> db.rollback() web2py のモデル・ビュー・コントロール のコードは、web2pyによって制御コードが付加されます。 このため、より細かな制御を望まない限り、コミット・ロールバックを記述する必要はありません。 参考: `commit and rollback `_ | `コミットとロールバック `_ .. method:: DAL.executesql(query[, placeholders, as_dict, fields, colnames ]) -> 実行結果 SQL文を実行できます。 :: >>> print db.executesql('select * from person') [(1, u'Syble Zee'), (2, u'Nathanial Azzano'), (3, u'Loreen Depierre')] >>> print db.executesql('select * from numbers;') [(1, 8, 71, 799), (2, 954, 364, 402)] DALではインデックス作成は複雑になるのでサポートしていません。必要なインデックスはこのコマンドを使用して作成可能です。 :: >>> db.executesql('CREATE INDEX IF NOT EXISTS myidx ON person (name);') [] query SQL文を設定します。 placeholders プレースホルダ(Queryの置き換え)変数を指定できます。 プレースホルダの構文はDALでは解析されないため、データベースエンジン・ドライバに依存します。 :: >>> print db.executesql('select * from person where id=:test', placeholders={'test':1}) [(1, u'Syble Zee')] as_dict SQL文の実行結果を出力方法を変更できます。デフォルトはFalseです。Trueにした場合、辞書型で結果を出力します。 :: >>> print db.executesql('select * from person', as_dict=True) [{'id': 1, 'name': u'Syble Zee'}, {'id': 2, 'name': u'Nathanial Azzano'}, {'id': 3, 'name': u'Loreen Depierre'}] >>> print db.executesql('select * from numbers',as_dict=True) [{'a': 8, 'c': 799, 'b': 71, 'id': 1}, {'a': 954, 'c': 402, 'b': 364, 'id': 2}] fields SQL文の実行結果とフィールドをマッチングするために指定します。 指定は :ref:`class_field` オブジェクトをリストで指定します。 もし :ref:`class_table` オブジェクトで指定した場合、 テーブルに含まれる全てのフィールドを指定したことと同等になります。 このパラメータを指定すると結果は、通常のDALクエリと同様に :ref:`class_rows` オブジェクトで返ってきます。 fieldsを指定しない場合 :: >>> rows= db.executesql('select * from person,dog where person.id==dog.owner_id') >>> print rows [(1, u'Syble Zee', 1, 1, u'Guadalupe Dadlani'), (2, u'Nathanial Azzano', 2, 2, u'Sook Liechti'), (3, u'Loreen Depierre', 3, 3, u'Hong Burnet'), (3, u'Loreen Depierre', 4, 3, u'Melonie Osterloh')] Fieldオブジェクトで指定した場合 :: >>> rows= db.executesql('select * from person,dog where person.id==dog.owner_id', ... fields=[db.person.id, db.person.name, db.dog.id, db.dog.owner_id, db.dog.name]) >>> print rows person.id,person.name,dog.id,dog.owner_id,dog.name 1,Syble Zee,1,1,Guadalupe Dadlani 2,Nathanial Azzano,2,2,Sook Liechti 3,Loreen Depierre,3,3,Hong Burnet 3,Loreen Depierre,4,3,Melonie Osterloh Tableオブジェクトで指定した場合 :: >>> rows= db.executesql('select * from person,dog where person.id==dog.owner_id', ... fields=[db.person, db.dog]) colnames fieldsパラメータの代わりに、``テーブル名.フィールド名`` の形式で、実行結果とフィールドをマッチングさせます。 :: >>> rows= db.executesql('select * from person,dog where person.id==dog.owner_id', ... colnames=['person.id', 'person.name', 'dog.id', 'dog.owner_id', 'dog.name']) colnames は fields と同時に指定することも可能です。この場合、colnamesの指定値はフィールドのラベルになります。 >>> rows= db.executesql('select * from person,dog where person.id==dog.owner_id', ... fields=[db.person, db.dog], ... colnames=['person id', 'name', 'dog id', 'dog owner', 'dog name']) >>> for row in rows: ... print row['name'] +' - '+ row['dog name'] ... Syble Zee - Guadalupe Dadlani Nathanial Azzano - Sook Liechti Loreen Depierre - Hong Burnet Loreen Depierre - Melonie Osterloh なお web2py Book には fieldsとcolnamesを同時に指定する場合、fieldsには :ref:`class_expression` オブジェクトを 追加可能という記述がありますが、少なくともSQLiteでは動作しないようです。 戻り値 SQL文の実行結果を返します。 参考: `Raw SQL `_ | `生のSQL `_ .. method:: DAL.export_to_csv_file アプリケーションの全てのテーブルを、CSV形式でエクスポートします。 Rowsクラスの export_to_csv_file メソッドを内部でコールしています。 パラメータも同一です。詳細は :meth:`~dal.Rows.export_to_csv_file` を参照ください。 .. method:: DAL.import_from_csv_file CSVファイルから、アプリケーションの複数テーブルのインポートを行います。。 Tableクラスの import_from_csv_file メソッドを内部でコールしています。 パラメータも同一です。詳細は :meth:`~dal.Table.import_from_csv_file` を参照ください。 .. method:: DAL.tables() -> リスト値 定義されているデータベース一覧を返します。 :: >>> db.tables ['auth_user', 'auth_group', 'auth_membership', 'auth_permission', 'auth_event', 'auth_cas', 'numbers', 'person', 'dog', 'feed', 'cat', 'inventory', 'mouse'] 戻り値 テーブル一覧のリスト値 .. method:: DAL.smart_query(fields, text) -> Setインスタンス 自然言語でクエリを実行する、スマートクエリです。詳細は、 :ref:`smart_query` を参照してください。 .. _class_dal_special_method: 特殊メソッド ------------ DALクラスには、いくつか特殊なメソッドが存在します。今回ここでは DALインスタンスに対してテーブル名を辞書型で指定すると、 :ref:`class_table` インスタンスを返す特殊メソッドを紹介します。構文は次のようになります。 :: DALインスタンス[テーブル名] → Tableインスタンス このメッソドを利用した例としては、アクセス制御で利用する Auth テーブルを考えることができます。Authテーブルはカスタマイズが可能で、 テーブル名自体も変更できます。例えば、auth_user テーブルの名前を変更する場合は、auth.settings.table_user_name 属性値に 新しい名前を設定します。このテーブルの Tableインスタンスを取得したい場合、次のように直接名前を指定することも可能ですが、 ハードコーディングになってしまいます。 :: >>> rows = db(db.auth_user).select() >>> for row in rows: ... print row.first_name, row.last_name ... Datatodu Tacemapo Dumacesa Datomoce 次のように特殊メソッドを使った方法で指定すれば、名前を変更した場合にプログラムソースを変更する必要がなくなります。 :: >>> rows = db(db[auth.settings.table_user_name]).select() >>> for row in rows: ... print row.first_name, row.last_name ... Datatodu Tacemapo Dumacesa Datomoce 属性 ---- .. attribute:: DAL._dbname データベース名を保持する属性です。 :: >>> print db._dbname sqlite .. attribute:: DAL._lastsql 最後に実行したSQL文を保持する属性です。これは :meth:`~dal.DAL.executesql` メソッドを使った場合も使わない場合も、全て記録されます。 :: >>> rows = db().select(db.numbers.ALL) >>> print db._lastsql SELECT numbers.id, numbers.a, numbers.b, numbers.c FROM numbers; 参考: `Raw SQL `_ | `生のSQL `_ .. attribute:: DAL._timings データベースドライバーに渡された、SQL文と実行時間(秒)をタプルで保持しています。 :: >>> db._timings [('SELECT person.id, person.name, person.birthday FROM person WHERE (person.id> 0);', 0.004999876022338867), ("INSERT INTO person(name) VALUES ('test');", 0.003000020980834961)] .. attribute:: DAL._uri 接続文字列を保持する属性です。 :: >>> print db._uri sqlite://storage.sqlite ---- .. [#f1] Pythonのinstance型オブジェクトではありませんが、簡単に説明するために **インスタンス** という言葉を使用しています。