2.17. レコードバージョン管理

web2pyにはレコード操作に伴ってバージョンを管理する仕組みが、次のように幾つか用意されています。

  1. table クラスの _enable_record_versioning メソッドを使用したバージョン管理機能
  2. Auth クラスの enable_record_versioning メソッドを使用したバージョン管理機能
  3. Auth クラスの archive メソッドを、SQLFORMやCRUDのコールバック関数に指定するバージョン管理機能

Auth クラスは アクセス制御 -Access control で使用されます。つまり Authクラスのメソッドで提供しているバージョン管理機能は、 Authの付加機能という位置付けと考えて良いと思います。

これらの機能の詳細を、以下説明して行きます。説明には次のテーブルを使用します。

db.define_table('person',
    Field('name'),
    format='%(name)s')

2.17.1. Table._enable_record_versioning メソッドのバージョン管理

このメソッドでバージョン管理を行うためには、テーブルのモデルを次のように変更する必要があります。

db.define_table('person',
    Field('name'),
    auth.signature,
    format='%(name)s')

ここで、 auth.signature のフィールドを継承させています。これによって、次のフィールドが追加されます。

フィールド タイプ 説明
is_active boolean Trueの場合レコードが有効です。レコードが削除されるとFalseになります。デフォルトはTrueです。
created_on datetime レコード作成日時です。
created_by reference auth_user レコード作成者です。auth_userを参照します。
modified_on datetime レコード更新日時です。
modified_by reference auth_user レコード更新者です。auth_userを参照します。

バージョン管理するには、次のようにモデル定義でTableオブジェクトのメソッドを呼び出します。

db.person._enable_record_versioning()

この設定によって、次のことが自動で行われます。

  • テーブル名_archive 」(サンプル例では person_archive)というバージョン管理用のテーブルが作成されます。
  • メソッドを呼び出したテーブルのレコード更新・削除を行うと、「テーブル名_archive」に元のレコードが保存されます。
  • 設定したテーブルに コモンフィルタ がセットされ、is_active フィールドが True でない場合、フィルタによってデータから外されます。

テーブル名_archive テーブルは次のフィールドと共に、元のテーブルのフィールドを継承します。

フィールド タイプ 説明
current_record reference テーブル名 元のテーブルを参照します。
id id アーカイブテーブルのidフィールドです。

メソッドのパラメータについては、 _enable_record_versioning() を参照ください。

2.17.2. Auth.enable_record_versioning メソッドのバージョン管理

このメソッドは内部で、 _enable_record_versioning() を呼び出しています。 このため同様に動作しますが、バージョン管理を実施するテーブルの指定方法が異なります。

Warning

このメソッドはバグのため web2py バージョン 2.6.0 以前では、設定しても実際には 動作しません

例えばモデル定義で、テーブルに auth.signature を継承させると共に、

db.define_table('person',
    Field('name'),
    auth.signature,
    format='%(name)s')

次のように指定します。

auth.enable_record_versioning(db)

この場合 db データベースに含まれる全てのテーブルをチェックし、次の条件に合致するテーブルでバージョン管理が行われます。

  • id フィールドが存在します(特殊なレガシデータベースには存在しません、 レガシデータベースの利用 を参照)。
  • modified_on フィールドが存在します(対象テーブルは、auth.signature を継承しています)。
  • current_record という名前のフィールドが含まれません(対象テーブルには、アーカイブテーブルは含まれません)。

次のようにテーブルを指定することもできます。

auth.enable_record_versioning(tables=[db.person, db.dog])

この場合も前記の条件に合致しなければ、指定されたテーブルはバージョン管理されません。

メソッドのパラメータは以下に説明します。

Auth.enable_record_versioning(tables[, archive_db, archive_name, current_record, is_active])
tables
バージョン管理するテーブルをイテレータオブジェクトで指定します。 前記の条件に合致する場合に、実際にバージョン管理されます。 DAL インスタンスを指定した場合、そのデータベースに含まれる全てのテーブルが対象になります。
archive_db, archive_name, current_record, is_active
これらのパラメータは、_enable_record_versioning() メソッドのパラメータ説明を参照ください。

2.17.3. Auth.archive メソッドのバージョン管理

このメソッドを使用したバージョン管理では、 SQLFORMCRUD を利用しアーカイブデータを保管します。

Note

特殊な理由がない限り、このメソッドを使用するより Table._enable_record_versioning もしくは Auth.enable_record_versioning メソッドを利用した方が容易です。

メソッドの設定によって、次のことが自動で行われます。

  • テーブル名_archive 」(サンプル例では person_archive)というバージョン管理用のテーブルが作成されます。
  • メソッドを呼び出したテーブルのレコード更新・削除を行うと、「テーブル名_archive」に元のレコードが保存されます。

_enable_record_versioning() メソッドの動作とよく似ていますが、次の点が異なります。

  • 自動で作成されるバージョン管理用テーブル(テーブル名_archive)は、モデル定義として公開されません。
  • 対象テーブルは、auth.signature を継承する必要はなく、 (削除は is_active フィールドをFalseに変更するのではなく)実際にレコードがテーブルから 削除 されます。
  • あくまでも SQLFORMCRUD で設定した場合にバージョン管理が行われます。 独自にDALコマンドでレコード操作した場合は、バージョン管理は行われません。

それでは利用方法について解説します。

  1. 事前準備

    テーブルは、auth.signature を継承する必要はありませんが、更新日時・ユーザの情報がテーブルにないのは不都合です。 このため次のように、対象テーブルに保存日時と保存ユーザのフィールドを追加します。

    db.define_table('person',
        Field('name'),
        Field('saved_on', 'datetime',
              default=request.now, update=request.now, readable=False, writable=False),
        Field('saved_by', auth.settings.table_user,
              default=auth.user_id, update=auth.user_id, readable=False, writable=False),
        format='%(name)s')
    

    このメソッドが作成するアーカイブテーブルは、標準では非公開です。 もしアプリなどで使用する予定がある場合は、次のようにモデルでテーブルを定義します。

    db.define_table('person_archive',
                    Field('current_record', db.person, ondelete='NO ACTION'),
                    db.person)
    
    このテーブル定義では次のことが必要です。
    • テーブル名が、「 テーブル名_archive 」という名前です。
    • current_record 」という名前の、元テーブルを参照するフィールドが存在します。
    • 元のテーブルを継承します。

    これらのルールは後で説明するメソッドのパラメータで変更可能です。

    他に参照フィールド(current_record)の ondelete パラメータに、’NO ACTION’ を指定していることに注意してください。 このパラメータのデフォルト値は ‘CASCADE’ です。デフォルト値のままだと、元のテーブルのレコードを削除した場合、 アーカイブテーブルのレコードまで削除されてしまうことになります。

  2. SQLFORMでの利用

    SQLFORMでのサンプルを示します。

    def person():
        form = SQLFORM(db.person, request.args(0), True).process(onsuccess=auth.archive)
        return dict(form=form)
    

    personテーブルのレコードを挿入・更新・削除するコントローラ関数です。 フォーム入力完了時のコールバック関数(onsuccess)を auth.archive と指定しています。 コールバック関数を指定するのではなく、次のように記述することも可能です。

    def person():
        form = SQLFORM(db.person, request.args(0), True)
        if form.process().accepted:
            auth.archive(form)
        return dict(form=form)
    
  3. CRUDでの利用

    CRUDでのサンプルを示します。

    def data():
        crud.settings.create_onaccept = crud.archive
        crud.settings.update_onaccept = crud.archive
        return dict(form=crud())
    

    crud.achive は内部で auth.archive を呼び出しています。

    削除時にコールバックされる crud.settigns.delete_onaccept 属性もありますが、パラメータがRowsオブジェクトになるため、 crud.archive は設定できません。crud.settings.update_deletable が True の場合(デフォルト値は True)、 更新画面で削除用チェックボックスが表示されます。このため更新画面で削除時すれば、 crud.settings.update_onaccept に設定されたコールバック関数が呼び出されます。

    属性値に記述するのではなく、パラメータにコールバック関数を指定することもできます。

    def data_create():
        return dict(form=crud.create(db.person, onaccept=crud.archive))
    
    def data_update():
        return dict(form=crud.update(db.person,  request.args(0), onaccept=crud.archive))
    
  4. Auth.archive メソッドの詳細説明

    メソッドに渡すことが可能なパラメータについて、以下に説明します。

    Auth.archive(form[, archive_table, current_record, archive_current, fields])
    form

    FORMオブジェクトを渡します。

    archive_table

    アーカイブテーブル・オブジェクトを指定します。デフォルト値は None です。 None の場合は、「 テーブル名_archive 」となります。 指定する場合は、アーカイブテーブルをモデル定義しておく必要があります。

    current_record

    アーカイブテーブルの元のレコードを参照するフィールド名を指定します。 デフォルトは、'current_record' です。 指定した名前のフィールドがアーカイブテーブルに追加され、 元のテーブルのレコードを参照するフィールドとして使用されます。

    archive_current

    アーカイブ方法を指定します。デフォルトは False です。 True を指定した場合、現在のレコードの値をアーカイブテーブルに格納します。 False では、更新前のレコードの値をアーカイブテーブルに格納します。

    fields

    アーカイブテーブルにレコード以外の例外フィールドを書きこむオプションです。 辞書型でフィールドと値を指定します。 指定するフィールドは事前にテーブルに定義しておく必要があります。フィールドと値は複数指定可能です。 デフォルトは None です。

    パラメータを指定したサンプルです。

    def person():
       form = SQLFORM(db.person, request.args(0), True).process(
                      onsuccess=lambda form: auth.archive(form, db.bk_person))
       return dict(form=form)
    

    アーカイブテーブルとして、bk_person を指定します。

    参考: form-Record versioningレコードのバージョニング

参考: Record versioningレコードのバージョン管理