W moim modelu mam:
class Alias(MyBaseModel):
remote_image = models.URLField(max_length=500, null=True, help_text="A URL that is downloaded and cached for the image. Only
used when the alias is made")
image = models.ImageField(upload_to='alias', default='alias-default.png', help_text="An image representing the alias")
def save(self, *args, **kw):
if (not self.image or self.image.name == 'alias-default.png') and self.remote_image :
try :
data = utils.fetch(self.remote_image)
image = StringIO.StringIO(data)
image = Image.open(image)
buf = StringIO.StringIO()
image.save(buf, format='PNG')
self.image.save(hashlib.md5(self.string_id).hexdigest() + ".png", ContentFile(buf.getvalue()))
except IOError :
pass
Który działa świetnie po raz pierwszy remote_image
zmiany.
Jak mogę pobrać nowy obraz, gdy ktoś zmodyfikował remote_image
alias? Po drugie, czy istnieje lepszy sposób buforowania zdalnego obrazu?
django
image
caching
django-models
Paul Tarjan
źródło
źródło
save()
, nadal będzie działał poprawnie.Używam następujących mixin:
Stosowanie:
Uwaga
Należy pamiętać, że to rozwiązanie działa dobrze tylko w kontekście bieżącego żądania. Dlatego nadaje się przede wszystkim do prostych przypadków. W środowisku współbieżnym, w którym wiele żądań może jednocześnie manipulować tym samym wystąpieniem modelu, zdecydowanie potrzebujesz innego podejścia.
źródło
Najlepszym sposobem jest
pre_save
sygnał. Być może nie było opcji jeszcze w 2009 roku, kiedy zadano to pytanie i udzielono na nie odpowiedzi, ale każdy, kto zobaczy to dzisiaj, powinien to zrobić w ten sposób:źródło
A teraz bezpośrednia odpowiedź: jednym ze sposobów sprawdzenia, czy wartość pola uległa zmianie, jest pobranie oryginalnych danych z bazy danych przed zapisaniem instancji. Rozważ ten przykład:
To samo dotyczy pracy z formularzem. Możesz go wykryć przy użyciu metody czyszczenia lub zapisywania ModelForm:
źródło
pk is not None
to sprawdzało , nie dotyczy to na przykład używania UUIDField. To tylko zła rada.@transaction.atomic
Od czasu wydania Django 1.8 możesz użyć metody class from_db do buforowania starej wartości obrazu remote_image. Następnie w oszczędzania metodzie można porównać stare i nowe wartości pola, aby sprawdzić, czy wartość została zmieniona.
źródło
new._loaded_remote_image = new.remote_image
?from_db
jest wywoływany przezrefresh_from_db
, atrybuty instancji (tj. Załadowane lub poprzednie) nie są aktualizowane. W rezultacie, nie mogę znaleźć żadnego powodu, dlaczego tak jest lepiej niż__init__
jak trzeba jeszcze obsłużyć 3 przypadki:__init__
/from_db
,refresh_from_db
, isave
.Zauważ, że śledzenie zmian pola jest dostępne w django-model-utils.
https://django-model-utils.readthedocs.org/en/latest/index.html
źródło
Jeśli korzystasz z formularza, możesz użyć zmienionych danych formularza ( dokumenty ):
źródło
Jestem trochę spóźniony na imprezę, ale znalazłem również to rozwiązanie: Django Dirty Fields
źródło
Od Django 1.8 istnieje
from_db
metoda, jak wspomina Serge. W rzeczywistości dokumenty Django obejmują ten konkretny przypadek użycia jako przykład:https://docs.djangoproject.com/en/dev/ref/models/instances/#customizing-model-loading
źródło
Działa to dla mnie w Django 1.8
źródło
Możesz użyć zmian modelu django, aby to zrobić bez dodatkowego wyszukiwania bazy danych:
źródło
Kolejna późna odpowiedź, ale jeśli chcesz tylko sprawdzić, czy nowy plik został przesłany do pola pliku, spróbuj tego: (na podstawie komentarza Christophera Adamsa do linku http://zmsmith.com/2010/05/django -check-if-a-field-has- change / in w komentarzu zach tutaj)
Zaktualizowany link: https://web.archive.org/web/20130101010327/http://zmsmith.com:80/2010/05/django-check-if-a-field-has-changed/
źródło
pre_save
odbiorniku. Dziękujemy za udostępnienie tego!Optymalnym rozwiązaniem jest prawdopodobnie takie, które nie obejmuje dodatkowej operacji odczytu bazy danych przed zapisaniem instancji modelu ani żadnej dalszej biblioteki django. Dlatego preferowane są rozwiązania Laffuste. W kontekście strony administratora można po prostu zastąpić
save_model
-method i wywołaćhas_changed
tam metodę formularza , tak jak w powyższej odpowiedzi Siona. Dochodzisz do czegoś takiego, korzystając z przykładowego ustawienia Siona, ale używając,changed_data
aby uzyskać każdą możliwą zmianę:save_model
:https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.save_model
changed_data
metoda dla pola:https://docs.djangoproject.com/en/1.10/ref/forms/api/#django.forms.Form.changed_data
źródło
Chociaż tak naprawdę to nie odpowiada na twoje pytanie, zrobiłbym to w inny sposób.
Po prostu wyczyść
remote_image
pole po pomyślnym zapisaniu lokalnej kopii. Następnie w metodzie zapisywania zawsze możesz zaktualizować obraz, gdyremote_image
nie jest pusty.Jeśli chcesz zachować odniesienie do adresu URL, możesz użyć nieedytowalnego pola boolowskiego do obsługi flagi buforowania zamiast
remote_image
samego pola.źródło
Miałem taką sytuację, zanim moje rozwiązanie polegało na zastąpieniu
pre_save()
metody docelowej klasy pola, która zostanie wywołana tylko wtedy, gdy zmieniono poleprzydatne w przykładzie FileField:
Wada:
nieprzydatne, jeśli chcesz wykonać dowolną operację (post_save), taką jak użycie utworzonego obiektu w pewnym zadaniu (jeśli pewne pole uległo zmianie)
źródło
poprawiając odpowiedź @josh dla wszystkich pól:
dla wyjaśnienia, getattr działa tak, aby uzyskać pola takie jak
person.name
łańcuchy (tjgetattr(person, "name")
źródło
Rozszerzyłem mixin @livskiy w następujący sposób:
a DictField to:
można go wykorzystać, rozszerzając go w swoich modelach. Podczas synchronizacji / migracji zostanie dodane pole _dict, w którym będzie przechowywany stan obiektów
źródło
Co powiesz na korzystanie z rozwiązania Davida Cramera:
http://cramer.io/2010/12/06/tracking-changes-to-fields-in-django/
Miałem sukces, używając go w następujący sposób:
źródło
Modyfikacja odpowiedzi @ ivanperelivskiy:
get_fields
Zamiast tego używa metody publicznej django 1.10 . To sprawia, że kod jest bardziej odporny na przyszłość, ale co ważniejsze, zawiera także klucze obce i pola, w których editable = False.Dla odniesienia tutaj jest implementacja
.fields
źródło
Oto inny sposób na zrobienie tego.
Zgodnie z dokumentacją: sprawdzanie poprawności obiektów
„Drugim krokiem, który wykonuje full_clean (), jest wywołanie Model.clean (). Ta metoda powinna zostać przesłonięta, aby wykonać niestandardowe sprawdzenie poprawności w twoim modelu. Ta metoda powinna być użyta do zapewnienia niestandardowego sprawdzania poprawności modelu i do modyfikowania atrybutów w twoim modelu, jeśli jest to pożądane . Możesz na przykład użyć go do automatycznego podania wartości dla pola lub do sprawdzenia poprawności, która wymaga dostępu do więcej niż jednego pola: „
źródło
Istnieje atrybut __dict__, który ma wszystkie pola jako klucze i wartość jako wartości pól. Możemy więc po prostu porównać dwa z nich
Wystarczy zmienić funkcję zapisu modelu na funkcję poniżej
Przykładowe użycie:
daje wynik tylko z tymi zmienionymi polami
źródło
Bardzo późno do gry, ale jest to wersja odpowiedzi Chrisa Pratta, która chroni przed warunkami wyścigowymi, poświęcając wydajność, używając
transaction
bloku iselect_for_update()
źródło
jako rozszerzenie odpowiedzi SmileyChris, możesz dodać do modelu pole daty i godziny dla ostatniej aktualizacji i ustawić pewien limit maksymalnego wieku, na jaki pozwolisz mu dotrzeć przed sprawdzeniem zmiany
źródło
Mixin z @ivanlivski jest świetny.
Rozszerzyłem to na
Zaktualizowany kod jest dostępny tutaj: https://github.com/sknutsonsf/python-contrib/blob/master/src/django/utils/ModelDiffMixin.py
Aby pomóc ludziom, którzy nie znają języka Python lub Django, podam pełniejszy przykład. To szczególne zastosowanie polega na pobraniu pliku od dostawcy danych i upewnieniu się, że rekordy w bazie danych odzwierciedlają ten plik.
Mój obiekt modelu:
Klasa ładująca plik ma następujące metody:
źródło
Jeśli nie interesuje Cię
save
metoda zastępowania , możesz to zrobićźródło