En mi modelo tengo:
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
Lo cual funciona muy bien por primera vez los remote_image
cambios.
¿Cómo puedo obtener una nueva imagen cuando alguien ha modificado remote_image
el alias? Y en segundo lugar, ¿hay una mejor manera de almacenar en caché una imagen remota?
django
image
caching
django-models
Paul Tarjan
fuente
fuente
save()
vuelva a llamarlo , seguirá funcionando correctamente.Yo uso siguiente mixin:
Uso:
Nota
Tenga en cuenta que esta solución funciona bien solo en el contexto de la solicitud actual. Por lo tanto, es adecuado principalmente para casos simples. En un entorno concurrente donde múltiples solicitudes pueden manipular la misma instancia de modelo al mismo tiempo, definitivamente necesita un enfoque diferente.
fuente
La mejor manera es con una
pre_save
señal. Puede que no haya sido una opción en el '09 cuando se hizo y respondió esta pregunta, pero cualquiera que vea esto hoy debería hacerlo de esta manera:fuente
Y ahora para una respuesta directa: una forma de verificar si el valor del campo ha cambiado es obtener datos originales de la base de datos antes de guardar la instancia. Considere este ejemplo:
Lo mismo se aplica cuando se trabaja con un formulario. Puede detectarlo en el método de limpieza o guardado de un ModelForm:
fuente
pk is not None
que no se aplica, por ejemplo, si usa un UUIDField Esto es solo un mal consejo.@transaction.atomic
Desde el lanzamiento de Django 1.8, puede usar from_db classmethod para almacenar en caché el valor anterior de remote_image. Luego, en el método de guardar , puede comparar el valor antiguo y el nuevo del campo para verificar si el valor ha cambiado.
fuente
new._loaded_remote_image = new.remote_image
?from_db
se llama porrefresh_from_db
, los atributos de la instancia (es decir, cargados o anteriores) no se actualizan. Como resultado, no puedo encontrar ninguna razón por la que esto es mejor que__init__
ya que todavía necesita manejar 3 casos:__init__
/from_db
,refresh_from_db
, ysave
.Tenga en cuenta que el seguimiento de cambios de campo está disponible en django-model-utils.
https://django-model-utils.readthedocs.org/en/latest/index.html
fuente
Si está usando un formulario, puede usar el formulario changed_data ( docs ) del formulario :
fuente
Llego un poco tarde a la fiesta, pero también encontré esta solución: Django Dirty Fields
fuente
A partir de Django 1.8, existe el
from_db
método, como Serge menciona. De hecho, los documentos de Django incluyen este caso de uso específico como ejemplo:https://docs.djangoproject.com/en/dev/ref/models/instances/#customizing-model-loading
fuente
Esto funciona para mí en Django 1.8
fuente
Puede usar django-model-changes para hacer esto sin una búsqueda adicional en la base de datos:
fuente
Otra respuesta tardía, pero si solo está tratando de ver si un nuevo archivo se ha cargado en un campo de archivo, intente esto: (adaptado del comentario de Christopher Adams en el enlace http://zmsmith.com/2010/05/django -check-if-a-field-has-changed / en el comentario de zach aquí)
Enlace actualizado: https://web.archive.org/web/20130101010327/http://zmsmith.com:80/2010/05/django-check-if-a-field-has-changed/
fuente
pre_save
receptor. ¡Gracias por compartir esto!La solución óptima es probablemente una que no incluya una operación de lectura de base de datos adicional antes de guardar la instancia del modelo, ni ninguna otra biblioteca django. Es por eso que las soluciones de laffuste son preferibles. En el contexto de un sitio de administración, uno simplemente puede anular el
save_model
método e invocar elhas_changed
método del formulario allí, tal como en la respuesta anterior de Sion. Llegas a algo como esto, recurriendo a la configuración de ejemplo de Sion pero usandochanged_data
para obtener todos los cambios posibles:save_model
:https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.save_model
changed_data
Método incorporado para un campo:https://docs.djangoproject.com/en/1.10/ref/forms/api/#django.forms.Form.changed_data
fuente
Si bien esto en realidad no responde a su pregunta, abordaría esto de una manera diferente.
Simplemente borre el
remote_image
campo después de guardar con éxito la copia local. Luego, en su método de guardar, siempre puede actualizar la imagen siempreremote_image
que no esté vacía.Si desea mantener una referencia a la URL, puede usar un campo booleano no editable para manejar la bandera de almacenamiento en caché en lugar del
remote_image
campo en sí.fuente
Tuve esta situación antes de que mi solución fuera anular el
pre_save()
método de la clase de campo de destino, seinvocará solo si el campo se ha cambiado útil con el ejemplo de FileField:
desventaja:
no es útil si desea realizar alguna operación (post_save) como usar el objeto creado en algún trabajo (si cierto campo ha cambiado)
fuente
mejorando la respuesta @josh para todos los campos:
solo para aclarar, el getattr funciona para obtener campos como
person.name
con cadenas (es decirgetattr(person, "name")
fuente
He extendido la mezcla de @livskiy de la siguiente manera:
y el DictField es:
se puede usar extendiéndolo en sus modelos, se agregará un campo _dict cuando sincronice / migre y ese campo almacenará el estado de sus objetos
fuente
¿Qué tal usar la solución de David Cramer?
http://cramer.io/2010/12/06/tracking-changes-to-fields-in-django/
He tenido éxito al usarlo así:
fuente
Una modificación a la respuesta de @ ivanperelivskiy:
Esto utiliza el método público de django 1.10
get_fields
lugar. Esto hace que el código sea más a prueba de futuro, pero lo más importante también incluye claves externas y campos donde editable = False.Como referencia, aquí está la implementación de
.fields
fuente
Aquí hay otra forma de hacerlo.
Según la documentación: validando objetos
"El segundo paso que realiza full_clean () es llamar a Model.clean (). Este método debe anularse para realizar una validación personalizada en su modelo. Este método debe usarse para proporcionar una validación de modelo personalizada y para modificar atributos en su modelo si lo desea Por ejemplo, podría usarlo para proporcionar automáticamente un valor para un campo, o para realizar una validación que requiere acceso a más de un solo campo: "
fuente
Hay un atributo __dict__ que tiene todos los campos como claves y valores como valores de campo. Entonces podemos comparar dos de ellos
Simplemente cambie la función de guardar del modelo a la siguiente función
Ejemplo de uso:
produce resultados con solo aquellos campos que han sido cambiados
fuente
Muy tarde al juego, pero esta es una versión de la respuesta de Chris Pratt que protege contra las condiciones de carrera al tiempo que sacrifica el rendimiento, mediante el uso de un
transaction
bloqueo yselect_for_update()
fuente
Como una extensión de la respuesta de SmileyChris, puede agregar un campo de fecha y hora al modelo para last_updated, y establecer algún tipo de límite para la edad máxima a la que lo dejará llegar antes de verificar un cambio
fuente
El mixin de @ivanlivski es genial.
Lo he extendido a
El código actualizado está disponible aquí: https://github.com/sknutsonsf/python-contrib/blob/master/src/django/utils/ModelDiffMixin.py
Para ayudar a las personas nuevas en Python o Django, daré un ejemplo más completo. Este uso particular es tomar un archivo de un proveedor de datos y garantizar que los registros en la base de datos reflejen el archivo.
Mi objeto modelo:
La clase que carga el archivo tiene estos métodos:
fuente
Si no encuentra interés en anular el
save
método, puede hacerlofuente