2010-12-18 15 views
11

連絡先データ(メンバーシップ番号、名、姓など)を持つCSVファイルをインポートできるDjangoアプリケーションがあります。Python/Djangoを使用して "元に戻す"機能を実装する方法

ファイルをインポートすると、アプリケーションは一致するレコードと、1)一致するレコードがない場合は新しいレコードを挿入します.2)既存のデータを新しいデータで更新します。

私の質問は:ユーザーがインポート操作を取り消し、バック元の状態に複数レコードを元に戻すことができるように、Djangoのか、ストレートのPythonを使用して、元に戻す機能を実装するための最良の方法は何ですか?

私の最初の考えは、この(擬似コード)のような表を作成するには、次のとおりです。

Table HISTORY 
    unique_id 
    record_affected_id 
    old_value 
    new_value 

次に、ユーザは、私が彼らのトランザクションに関連付けられていますUNIQUE_IDを検索し、すべてのレコードを設定することができ、「元に戻す」をクリックした場合そのトランザクションによってold_valueに影響を受けます。

これを行う簡単な方法がないか、誰かがこのようなことを経験しているかどうかは疑問です。

答えて

10

django-reversionをご覧ください。 Djangoのバージョン管理機能を提供します。既存のプロジェクトに簡単に追加できます。

"現在の"ポインタアプローチを採用していません。代わりに、保存されるたびにオブジェクトをシリアル化し、別のVersionモデルに格納します。このモデルには、このオブジェクトを指す汎用外部キーがあります。 (リレーションシップフィールドはデフォルトでプライマリキーとしてシリアル化されています)また、VersionRevisionに柔軟にグループ化することができます。

だからあなたはそのような何かを行うことができます。ユーザーは、CSVをアップロードすると

  • は、ちょうどいつものように、変更を保存しますが、ない関数に@revision.create_on_successデコレータを追加輸入ので、それによって作られたレコードへの変更関数は1つのリビジョンの下に格納されます。
  • ユーザーが「元に戻す」を押すと、最新のリビジョンに戻すだけです。ここで

は、それはそれはあなたが唯一のユーザーのインポートCSVをリビジョンを作成するという事実に依存::

@revision.create_on_success 
def import_csv(request, csv): 
    # Old versions of all objects save()d here will 
    # belong to single revision. 

def undo_last_csv_import(request): 
    # First, get latest revision saved by this user. 
    # (Assuming you create revisions only when user imports a CSV 
    # and do not version control other data.) 
    revision = Revision.objects.filter(user=request.user)\ 
     .order_by('-date_created')[0] 
    # And revert it, delete=True means we want to delete 
    # any newly added records as well 
    revision.revert(delete=True) 

を行うことができる方法です。つまり、他のデータをバージョン管理する予定がある場合は、最新のインポートの影響を受けるレコードを取得するためのフラグを実装する必要があります。次に、このフラグでレコードを取得し、最新の保存済みバージョンを取得し、そのバージョンが属するリビジョン全体を元に戻すことができます。この::

def undo_last_csv_import(request): 
    some_record = Record.objects.by_user(request.user).from_the_last_import()[0] 
    latest_saved_version_of_some_record = Version.objects.get_for_date(
     some_record, 
     datetime.now(), # The latest saved Version at the moment. 
     ) 
    # Revert all versions that belong to the same revision 
    # as the version we got above. 
    latest_saved_version_of_some_record.revision.revert() 

のようにそれは美しい解決策ではないですが、最も確かにこのアプリで、より良いそれを行うための方法があります。 django-reversionがどのように機能しているかをよく理解するためのコードを見てみることをお勧めします。文書化されていない関数を見つけることができませんでした。^_^D

(ドキュメントでも良いですが、彼らはVersion.objects.get_for_date(your_model, date)を書くすなわち、私のために誤解を招くビットであることが判明し、your_modelが実際にモデルインスタンスです。)

更新:ジャンゴ-復帰上記のコードにはあまり依存せず、wikiのバージョンを管理してください。&リビジョンはdjangoの管理者の外にあります。たとえば、リビジョンコメントは既にサポートされているため、少し単純化される可能性があります。

3

バージョンコントロールが必要です。問題はPythonやDjangoではなく、これを行うためのデータベースの設計方法です。 1つの一般的な方法は、一意のIDを持つ文書を保存し、どちらが「最新」であるかを追跡することです。元に戻すと、現在のポインタを古いリビジョンに戻すことができます。これは、私が見る限り、あなたがしていることです。

これは一般的なやり方ですが、それが最善かどうかはわかりません。私は他の方法を見たことがありません。これは、それが最高であることを意味するかもしれません。あるいは、最善の方法は自明ではありません。 :-)

Djangoの一般的な方法でこれを行うのはおそらく難しい問題ですが、Djangoアプリケーションでカスタム方法でサポートすると簡単になります。

「将来の」リビジョンのものを編集して一度に一連のドキュメントを段階的な種類のコンテンツの方法で公開する方法など、楽しい(not)問題が発生します。しかし、うまくいけばそれは必要ない。 :-)

1

あなたの履歴テーブルは、元に戻す操作を実行するためにnew_valueフィールドを必要としない点を除いて、正常に見えます。そして、そう、「アンドゥ」がしばしば実装される(他の選択肢は、レナートがすべてのレコードにバージョン番号を入れるアプローチです)。別のジャーナルテーブルの利点は、通常のクエリでバージョン番号を処理する必要がないことです。

関連する問題