Dans mon modèle, j'ai:
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
Ce qui fonctionne très bien pour la première fois les remote_image
changements.
Comment puis-je récupérer une nouvelle image lorsque quelqu'un a modifié remote_image
l'alias? Et deuxièmement, existe-t-il un meilleur moyen de mettre en cache une image distante?
django
image
caching
django-models
Paul Tarjan
la source
la source
save()
le ENCORE, il fonctionnera toujours correctement.J'utilise le mixin suivant:
Usage:
Remarque
Veuillez noter que cette solution fonctionne bien dans le contexte de la demande actuelle uniquement. Il convient donc principalement aux cas simples. Dans un environnement simultané où plusieurs demandes peuvent manipuler la même instance de modèle en même temps, vous avez certainement besoin d'une approche différente.
la source
Le meilleur moyen est avec un
pre_save
signal. Peut-être n'était-ce pas une option en 2009 quand cette question a été posée et répondue, mais quiconque le voit aujourd'hui devrait le faire de cette façon:la source
Et maintenant, pour une réponse directe: une façon de vérifier si la valeur du champ a changé est de récupérer les données d'origine de la base de données avant d'enregistrer l'instance. Considérez cet exemple:
La même chose s'applique lorsque vous travaillez avec un formulaire. Vous pouvez le détecter à l'aide de la méthode de nettoyage ou d'enregistrement d'un ModelForm:
la source
pk is not None
cela ne s'applique pas, par exemple si vous utilisez un UUIDField. C'est juste un mauvais conseil.@transaction.atomic
Depuis la sortie de Django 1.8, vous pouvez utiliser la méthode de classe from_db pour mettre en cache l'ancienne valeur de remote_image. Ensuite, dans la méthode de sauvegarde , vous pouvez comparer l'ancienne et la nouvelle valeur du champ pour vérifier si la valeur a changé.
la source
new._loaded_remote_image = new.remote_image
?from_db
est appelé parrefresh_from_db
, les attributs de l'instance (c'est-à-dire chargés ou précédents) ne sont pas mis à jour. Par conséquent, je ne peux trouver aucune raison pour laquelle cela vaut mieux que__init__
que vous avez encore besoin de gérer 3 cas:__init__
/from_db
,refresh_from_db
, etsave
.Notez que le suivi des modifications de champ est disponible dans django-model-utils.
https://django-model-utils.readthedocs.org/en/latest/index.html
la source
Si vous utilisez un formulaire, vous pouvez utiliser les données modifiées du formulaire ( docs ):
la source
Je suis un peu en retard à la fête mais j'ai aussi trouvé cette solution: Django Dirty Fields
la source
Depuis Django 1.8, il y a la
from_db
méthode, comme le mentionne Serge. En fait, les documents Django incluent ce cas d'utilisation spécifique à titre d'exemple:https://docs.djangoproject.com/en/dev/ref/models/instances/#customizing-model-loading
la source
Cela fonctionne pour moi dans Django 1.8
la source
Vous pouvez utiliser django-model-changes pour ce faire sans recherche de base de données supplémentaire:
la source
Une autre réponse tardive, mais si vous essayez simplement de voir si un nouveau fichier a été téléchargé dans un champ de fichier, essayez ceci: (adapté du commentaire de Christopher Adams sur le lien http://zmsmith.com/2010/05/django -check-si-un-champ-a-changé / dans le commentaire de zach ici)
Lien mis à jour: https://web.archive.org/web/20130101010327/http://zmsmith.com:80/2010/05/django-check-if-a-field-has-changed/
la source
pre_save
récepteur. Merci d'avoir partagé ça!La solution optimale est probablement celle qui n'inclut pas d'opération de lecture de base de données supplémentaire avant d'enregistrer l'instance de modèle, ni aucune autre bibliothèque django. C'est pourquoi les solutions de laffuste sont préférables. Dans le contexte d'un site d'administration, on peut simplement remplacer la
save_model
méthode -m et y invoquer lahas_changed
méthode du formulaire , comme dans la réponse de Sion ci-dessus. Vous arrivez à quelque chose comme ça, en vous inspirant du paramètre d'exemple de Sion mais en utilisantchanged_data
pour obtenir tous les changements possibles:save_model
:https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.save_model
changed_data
-method pour un champ:https://docs.djangoproject.com/en/1.10/ref/forms/api/#django.forms.Form.changed_data
la source
Bien que cela ne réponde pas réellement à votre question, je procéderais différemment.
Effacez simplement le
remote_image
champ après avoir enregistré avec succès la copie locale. Ensuite, dans votre méthode d'enregistrement, vous pouvez toujours mettre à jour l'image à chaque foisremote_image
n'est pas vide.Si vous souhaitez conserver une référence à l'URL, vous pouvez utiliser un champ booléen non modifiable pour gérer l'indicateur de mise en cache plutôt que le
remote_image
champ lui-même.la source
J'ai eu cette situation avant que ma solution ne remplace la
pre_save()
méthode de la classe de champ cible, elle ne sera appelée que si le champ a été modifiéutile avec l'exemple FileField:
inconvénient:
pas utile si vous souhaitez effectuer une opération (post_save) comme utiliser l'objet créé dans un travail (si certains champs ont changé)
la source
amélioration de la réponse @josh pour tous les domaines:
juste pour clarifier, le getattr fonctionne pour obtenir des champs comme
person.name
avec des chaînes (iegetattr(person, "name")
la source
J'ai étendu le mixin de @livskiy comme suit:
et le DictField c'est:
il peut être utilisé en l'étendant dans vos modèles un champ _dict sera ajouté lorsque vous synchroniserez / migrez et ce champ stockera l'état de vos objets
la source
Que diriez-vous d'utiliser la solution de David Cramer:
http://cramer.io/2010/12/06/tracking-changes-to-fields-in-django/
J'ai réussi à l'utiliser comme ceci:
la source
Une modification de la réponse de @ ivanperelivskiy:
Cela utilise à la place la méthode publique de django 1.10
get_fields
. Cela rend le code plus à l'épreuve du temps, mais plus important encore, inclut également les clés étrangères et les champs où editable = False.Pour référence, voici l'implémentation de
.fields
la source
Voici une autre façon de procéder.
Selon la documentation: validation des objets
"La deuxième étape effectuée par full_clean () consiste à appeler Model.clean (). Cette méthode doit être remplacée pour effectuer une validation personnalisée sur votre modèle. Cette méthode doit être utilisée pour fournir une validation de modèle personnalisée et pour modifier les attributs de votre modèle si vous le souhaitez. Par exemple, vous pouvez l'utiliser pour fournir automatiquement une valeur pour un champ ou pour effectuer une validation qui nécessite l'accès à plusieurs champs: "
la source
Il existe un attribut __dict__ qui a tous les champs comme clés et la valeur comme valeurs de champ. Nous pouvons donc simplement comparer deux d'entre eux
Modifiez simplement la fonction de sauvegarde du modèle en fonction ci-dessous
Exemple d'utilisation:
donne une sortie avec uniquement les champs qui ont été modifiés
la source
Très tard dans le jeu, mais c'est une version de la réponse de Chris Pratt qui protège contre les conditions de course tout en sacrifiant les performances, en utilisant un
transaction
bloc etselect_for_update()
la source
en tant qu'extension de la réponse de SmileyChris, vous pouvez ajouter un champ datetime au modèle pour last_updated et définir une sorte de limite pour l'âge maximum auquel vous le laisserez arriver avant de vérifier une modification
la source
Le mixin de @ivanlivski est super.
Je l'ai étendu à
Le code mis à jour est disponible ici: https://github.com/sknutsonsf/python-contrib/blob/master/src/django/utils/ModelDiffMixin.py
Pour aider les nouveaux utilisateurs de Python ou Django, je vais donner un exemple plus complet. Cette utilisation particulière consiste à extraire un fichier d'un fournisseur de données et à garantir que les enregistrements de la base de données reflètent le fichier.
Mon objet modèle:
La classe qui charge le fichier a ces méthodes:
la source
Si vous ne trouvez pas d'intérêt pour la
save
méthode prioritaire , vous pouvez le fairela source