365 votes

Django: En sauvegardant, comment pouvez-vous vérifier si un champ a changé?

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 bien pour la première fois, les changements remote_image .

Comment puis-je récupérer une nouvelle image lorsque quelqu'un a modifié le remote_image sur l'alias? Et deuxièmement, existe-t-il un meilleur moyen de mettre en cache une image distante?

530voto

Josh Points 2820

Si c’est un peu tard, je voudrais jeter cette solution pour les autres qui viennent sur ce post. Essentiellement, vous souhaitez substituer la méthode de sorte que vous gardez une copie de la valeur d’origine. Cela rend donc que vous n’avez pas à faire une autre recherche de DB (qui est toujours une bonne chose).

268voto

ivanlivski Points 837

J'utilise le mixin suivant:

 from django.forms.models import model_to_dict


class ModelDiffMixin(object):
    """
    A model mixin that tracks model fields' values and provide some useful api
    to know what fields have been changed.
    """

    def __init__(self, *args, **kwargs):
        super(ModelDiffMixin, self).__init__(*args, **kwargs)
        self.__initial = self._dict

    @property
    def diff(self):
        d1 = self.__initial
        d2 = self._dict
        diffs = [(k, (v, d2[k])) for k, v in d1.items() if v != d2[k]]
        return dict(diffs)

    @property
    def has_changed(self):
        return bool(self.diff)

    @property
    def changed_fields(self):
        return self.diff.keys()

    def get_field_diff(self, field_name):
        """
        Returns a diff for field if it's changed and None otherwise.
        """
        return self.diff.get(field_name, None)

    def save(self, *args, **kwargs):
        """
        Saves model and set initial state.
        """
        super(ModelDiffMixin, self).save(*args, **kwargs)
        self.__initial = self._dict

    @property
    def _dict(self):
        return model_to_dict(self, fields=[field.name for field in
                             self._meta.fields])
 

Usage:

 >>> p = Place()
>>> p.has_changed
False
>>> p.changed_fields
[]
>>> p.rank = 42
>>> p.has_changed
True
>>> p.changed_fields
['rank']
>>> p.diff
{'rank': (0, 42)}
>>> p.categories = [1, 3, 5]
>>> p.diff
{'categories': (None, [1, 3, 5]), 'rank': (0, 42)}
>>> p.get_field_diff('categories')
(None, [1, 3, 5])
>>> p.get_field_diff('rank')
(0, 42)
>>>
 

209voto

Chris Pratt Points 53859

Meilleure façon est d’une `` signal. Peut-être pas une option retour en ' 09 lorsque cette question a été posée et répondue, mais n’importe qui voyant ce aujourd'hui devrait faire de cette façon :

157voto

zgoda Points 8549

Et maintenant pour répondre directement : une façon de vérifier si la valeur pour le champ a changé est pour récupérer les données originales de base de données avant d’enregistrer l’instance. Considérez cet exemple :

2voto

SmileyChris Points 5405

Alors que ce n’est pas vraiment répondre à votre question, je voudrais aller à ce sujet de manière différente.

Tout simplement clair la champ après avoir enregistré avec succès la copie locale. Ensuite, dans votre sauvegarde méthode vous pouvez toujours mettre à jour l’image chaque fois que 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 au lieu de `` sur le terrain lui-même.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X