В моей модели у меня есть:
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
Который отлично работает в первый раз remote_image
изменения.
Как я могу получить новое изображение, если кто-то изменил remote_image
псевдоним? А во-вторых, есть ли лучший способ кэширования удаленного изображения?
django
image
caching
django-models
Пол Тарьян
источник
источник
save()
его снова, он все равно будет работать правильно.Я использую следующий миксин:
Использование:
Заметка
Обратите внимание, что это решение хорошо работает только в контексте текущего запроса. Таким образом, он подходит в первую очередь для простых случаев. В параллельной среде, где несколько запросов могут одновременно манипулировать одним и тем же экземпляром модели, вам определенно нужен другой подход.
источник
Лучший способ с
pre_save
сигналом. Возможно, не было выбора еще в '09, когда на этот вопрос задавали и отвечали, но любой, кто видит это сегодня, должен сделать это следующим образом:источник
А теперь прямой ответ: один из способов проверить, изменилось ли значение для поля, - это извлечь исходные данные из базы данных перед сохранением экземпляра. Рассмотрим этот пример:
То же самое относится и к работе с формой. Вы можете обнаружить это при чистом или сохраненном методе ModelForm:
источник
pk is not None
что это не относится, например, если вы используете UUIDField. Это просто плохой совет.@transaction.atomic
Начиная с выпуска Django 1.8, вы можете использовать метод класса from_db для кэширования старого значения remote_image. Затем в методе сохранения вы можете сравнить старое и новое значение поля, чтобы проверить, изменилось ли значение.
источник
new._loaded_remote_image = new.remote_image
?from_db
вызовеrefresh_from_db
, атрибуты экземпляра (то есть загруженные или предыдущие) не обновляются. В результате, я не могу найти причину , почему это лучше , чем ,__init__
как вам все еще нужно обрабатывать 3 случая:__init__
/from_db
,refresh_from_db
, иsave
.Обратите внимание, что отслеживание изменений поля доступно в django-model-utils.
https://django-model-utils.readthedocs.org/en/latest/index.html
источник
Если вы используете форму, вы можете использовать Измененные_данные формы ( документы ):
источник
Я немного опоздал на вечеринку, но я нашел и это решение: Django Dirty Fields
источник
Начиная с Django 1.8, есть
from_db
метод, как упоминает Серж. Фактически, документы Django включают этот конкретный пример использования в качестве примера:https://docs.djangoproject.com/en/dev/ref/models/instances/#customizing-model-loading
источник
Это работает для меня в Django 1.8
источник
Вы можете использовать django-model-changes, чтобы сделать это без дополнительного поиска в базе данных:
источник
Еще один поздний ответ, но если вы просто пытаетесь увидеть, был ли загружен новый файл в файловое поле, попробуйте это: (адаптировано из комментария Кристофера Адамса по ссылке http://zmsmith.com/2010/05/django -check-if-a-field-has-change / в комментарии Зака здесь)
Обновленная ссылка: https://web.archive.org/web/20130101010327/http://zmsmith.com:80/2010/05/django-check-if-a-field-has-changed/
источник
pre_save
приемнике. Спасибо, что поделились этим!Оптимальным решением, вероятно, является решение, которое не включает в себя дополнительную операцию чтения базы данных перед сохранением экземпляра модели или какую-либо дополнительную библиотеку django. Вот почему решения Лаффуста предпочтительнее. В контексте сайта администратора можно просто переопределить
save_model
-method и вызвать тамhas_changed
метод формы , как в ответе Сиона выше. Выchanged_data
получаете что-то вроде этого, опираясь на пример настройки Сиона, но используя для этого все возможные изменения:save_model
:https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.save_model
changed_data
метод для поля:https://docs.djangoproject.com/en/1.10/ref/forms/api/#django.forms.Form.changed_data
источник
Хотя это на самом деле не отвечает на ваш вопрос, я бы пошел по-другому.
Просто очистите
remote_image
поле после успешного сохранения локальной копии. Тогда в вашем методе сохранения вы всегда можете обновить изображение всякий раз, когдаremote_image
оно не пустое.Если вы хотите сохранить ссылку на URL, вы можете использовать не редактируемое логическое поле для обработки флага кэширования, а не
remote_image
само поле.источник
У меня была такая ситуация до того, как я решил переопределить
pre_save()
метод класса целевого поля, он будет вызываться только в том случае, если поле было изменено, чтополезно с примером FileField:
недостаток:
бесполезно, если вы хотите выполнить какую-либо (post_save) операцию, например, использовать созданный объект в каком-либо задании (если определенное поле изменилось)
источник
улучшение ответа @josh для всех полей:
просто чтобы уточнить, getattr работает, чтобы получить поля, как
person.name
со строками (т.е.getattr(person, "name")
источник
Я расширил миксин @livskiy следующим образом:
и DictField это:
его можно использовать, расширив его в ваших моделях; при синхронизации / миграции будет добавлено поле _dict, в котором будет храниться состояние ваших объектов.
источник
Как насчет использования решения Дэвида Крамера:
http://cramer.io/2010/12/06/tracking-changes-to-fields-in-django/
Я имел успех, используя это так:
источник
Модификация ответа @ ivanperelivskiy:
get_fields
Вместо этого используется открытый метод django 1.10 . Это делает код более перспективным для будущего, но, что более важно, также включает внешние ключи и поля, где editable = False.Для справки, вот реализация
.fields
источник
Вот еще один способ сделать это.
Согласно документации: проверка объектов
«Второй шаг, который выполняет full_clean (), - это вызов Model.clean (). Этот метод должен быть переопределен для выполнения пользовательской проверки вашей модели. Этот метод должен использоваться для обеспечения пользовательской проверки модели и, при желании, для изменения атрибутов вашей модели. Например, вы можете использовать его для автоматического предоставления значения для поля или для проверки, которая требует доступа к более чем одному полю: "
источник
Существует атрибут __dict__, в котором все поля являются ключами, а значения - значениями полей. Таким образом, мы можем просто сравнить два из них
Просто измените функцию сохранения модели на функцию ниже
Пример использования:
выводит только те поля, которые были изменены
источник
Очень поздно к игре, но это вариант ответа Криса Пратта, который защищает от условий гонки, жертвуя при этом производительностью, используя
transaction
блок иselect_for_update()
источник
как расширение ответа SmileyChris, вы можете добавить поле datetime в модель для last_updated и установить какое-то ограничение на максимальный возраст, который вы дадите ему, прежде чем проверять изменения
источник
Миксин от @ivanlivski отличный.
Я расширил это до
Обновленный код доступен здесь: https://github.com/sknutsonsf/python-contrib/blob/master/src/django/utils/ModelDiffMixin.py
Чтобы помочь новичкам в Python или Django, я приведу более полный пример. Это конкретное использование заключается в получении файла от поставщика данных и обеспечении того, чтобы записи в базе данных отражали этот файл.
Моя модель объекта:
Класс, который загружает файл, имеет следующие методы:
источник
Если вы не заинтересованы в переопределении
save
метода, вы можете сделатьисточник