2010-12-18 16 views
11

Mam aplikację Django, w której zezwalam użytkownikowi na zaimportowanie pliku CSV z danymi kontaktowymi (numer członkostwa, imię, nazwisko itp.).Jak zaimplementować funkcję "cofnij" za pomocą Pythona/Django

Po zaimportowaniu pliku aplikacja sprawdza bazę danych pod kątem odpowiedniego rekordu i: 1) wstawia nowy rekord, jeśli nie istnieje, lub 2) aktualizuje istniejące dane o nowe dane.

Moje pytanie brzmi: co to jest najlepszym sposobem, aby zaimplementować funkcję cofania, używając Django lub prosty Python, dzięki czemu użytkownik może cofnąć operację importowania i przywrócić wielu rekordy z powrotem do ich pierwotnego stanu?

Moje pierwsze myśli są utworzyć tabelę tak (pseudo kod):

Table HISTORY 
    unique_id 
    record_affected_id 
    old_value 
    new_value 

wtedy, gdy użytkownik kliknie „Cofnij” Mogę zajrzeć do unique_id, który jest związany z ich transakcji i ustawić każdy rekord wpływ tej transakcji na old_value.

Zastanawiam się, czy istnieje prostszy sposób, aby to zrobić, że brakuje mi, lub jeśli ktoś ma doświadczenie z czymś podobnym.

Odpowiedz

10

Spójrz na django-reversion. Zapewnia kontrolę wersji dla modeli Django. Można go łatwo dodać do istniejącego projektu.

Nie stosuje podejścia "bieżącego" wskaźnika. Zamiast tego serializuje obiekt za każdym razem, gdy jest zapisywany i zapisuje go w oddzielnym modelu Version z ogólnym kluczem obcym wskazującym na ten obiekt. (Pola relacji są domyślnie serializowane jako klucze podstawowe). Pozwala także na grupowanie Version s w Revision s w elastyczny sposób.

Więc można zrobić coś takiego:

  • Kiedy użytkownik przesyła plik CSV, zapisz zmiany jak zwykle, ale dodać @revision.create_on_success dekorator do funkcji, która robi import-tak, że wszelkie zmiany zapisów dokonanych przez które Funkcja zostanie zapisana pod jedną wersją.
  • Gdy użytkownik kliknie "Cofnij", po prostu przywróci ostatnią wersję.

Oto jak można to zrobić ::

@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) 

Polega ona na tym, że tworzysz wersje tylko wtedy, gdy użytkownik importuje pliki CSV. Oznacza to, że jeśli planujesz również kontrolę wersji innych danych, musisz zaimplementować jakąś flagę, dzięki której możesz uzyskać rekordy, których dotyczy najnowszy import. Następnie możesz uzyskać rekord za pomocą tej flagi, pobrać najnowszą zapisaną wersję i przywrócić całą wersję, do której należy wersja. W ten sposób:

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() 

To nie jest piękne rozwiązanie, z pewnością istnieją sposoby, aby zrobić to lepiej dzięki tej aplikacji. Polecam zajrzeć do kodu, aby lepiej zrozumieć, jak działa django-reversion - bardzo dobrze udokumentowany, nie mógł znaleźć funkcji bez docstruowania.^_^D

(Dokumentacja jest również dobra, ale okazało się być nieco mylące dla mnie, czyli piszą Version.objects.get_for_date(your_model, date), gdzie your_model jest faktycznie instancja modelu).

Aktualizacja: django-powrót jest aktywnie utrzymywany, więc nie należy polegać na powyższym kodzie i lepiej sprawdzić ich wiki, jak zarządzać wersjami & wersji poza adminem Django. Na przykład komentarze wersji są już obsługiwane, co może trochę uprościć.

3

Musisz mieć kontrolę wersji, a problem nie istnieje Python lub Django, ale raczej jak zaprojektować bazę danych, aby to zrobić. Jednym z typowych sposobów jest przechowywanie dokumentów z unikatowymi identyfikatorami i śledzenie, który z nich jest "aktualny". Cofnięcie jest tylko kwestią przeniesienia "bieżącego" wskaźnika do starszej wersji. To, o ile widzę, to, co robisz.

Chociaż jest to powszechny sposób robienia tego, nie wiem, czy to jest najlepsze. Nigdy nie widziałem innego sposobu, który może oznaczać, że jest najlepszy, lub że najlepszy sposób jest nieoczywisty. :-)

Wykonanie tego w sposób ogólny w Django jest prawdopodobnie trudnym zadaniem, ale będzie łatwiejsze, jeśli sprawisz, że aplikacja Django będzie je obsługiwać w niestandardowy sposób.

Następnie pojawia się zabawa (nie) Problemy, takie jak edycja rzeczy w "przyszłej" wersji, a następnie opublikowanie całego zestawu dokumentów na raz, w sposób inscenizacji treści. Ale mam nadzieję, że tego nie potrzebujesz. :-)

1

Twoja tabela historii wygląda dobrze, z tym że nie potrzebujesz pola new_value, aby wykonać cofanie. I tak, to "jak" cofnąć "jest często realizowane (inną alternatywą jest podejście Lennart do umieszczania numeru wersji we wszystkich rekordach). Zaletą oddzielnej tabeli dziennika jest to, że nie musisz zajmować się numerem wersji w zwykłych kwerendach.

Powiązane problemy