[英]How to implement an “undo” feature using Python/Django
我有一個Django應用程序,我允許用戶導入帶有聯系人數據的CSV文件(成員資格#,名字,姓氏等)。
當他們導入文件時,應用程序會檢查數據庫是否有匹配的記錄,並且:1)如果不存在匹配則插入新記錄,或者2)使用新數據更新現有數據。
我的問題是:使用Django或直接Python實現撤銷功能的最佳方法是什么,以便用戶可以撤消導入操作並將多個記錄恢復到原始狀態?
我最初的想法是創建一個這樣的表(偽代碼):
Table HISTORY
unique_id
record_affected_id
old_value
new_value
然后,如果用戶單擊“撤消”,我可以查找與其事務關聯的unique_id,並將受該事務影響的每條記錄設置為old_value。
我想知道是否有一種更簡單的方法可以做到這一點,我錯過了,或者如果有人有這樣的經歷。
看看django-reversion
。 它為Django模型提供版本控制。 可以輕松添加到現有項目中。
它不采用“當前”指針方法。 相反,它在每次保存對象時將對象序列化,並將其存儲在單獨的Version
模型中,並使用指向此對象的通用外鍵。 (關系字段被序列化為默認主鍵。)另外,它允許組Version
s轉換Revision
S IN的靈活方式。
所以你可以這樣做:
@revision.create_on_success
裝飾器添加到執行導入的功能中,以便該功能對記錄所做的任何更改都將存儲在單個修訂版本中。 這是怎么做的::
@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)
它依賴於僅在用戶導入CSV時才創建修訂的事實。 這意味着,如果您還打算對其他數據進行版本控制,那么您需要實現某種標志,通過該標志可以獲取受最新導入影響的記錄。 然后,您可以通過此標志獲取記錄,獲取最新保存的版本,並還原該版本所屬的整個修訂版。 像這樣::
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
如何工作 - 記錄得很好,找不到沒有docstring的函數。 ^ _ ^ d
(文檔也很好,但結果對我來說有點誤導,即他們寫了Version.objects.get_for_date(your_model, date)
,其中your_model實際上是一個模型實例。)
更新: django-reversion是主動維護的,所以不要依賴上面的代碼,並且更好地檢查他們的wiki如何管理django管理員之外的版本和修訂版。 例如,已經支持修訂注釋,這可能會簡化一些事情。
你需要有版本控制,問題不是Python或Django,而是如何設計數據庫來做到這一點。 一種常見的方法是存儲具有唯一ID的文檔並跟蹤哪個是“當前”。 然后撤銷只是將“當前”指針放回舊版本。 據我所知,這是你在做什么。
雖然這是常見的做法,但我不知道它是否是最好的。 我從未見過任何其他方式,這可能意味着它是最好的,或者最好的方式是不明顯的。 :-)
在Django中以通用方式執行此操作可能是一個難題,但如果您使Django應用程序以自定義方式支持它會更容易。
然后你會進入Fun(not)問題,比如如何編輯“未來”修訂版中的內容,然后一次性地發布一整套文檔。 但希望你不需要那個。 :-)
您的歷史記錄表看起來很好,除了您不需要new_value字段來執行撤消。 是的,經常實施“如何”撤銷“(另一種選擇是Lennart將版本號放入所有記錄的方法)。 單獨的日志表的優點是您不需要在常規查詢中處理版本號。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.