Django: При сохранении, как вы можете проверить, изменилось ли поле? - PullRequest
250 голосов
/ 31 августа 2009

В моей модели у меня есть:

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 на псевдониме? А во-вторых, есть ли лучший способ кэширования удаленного изображения?

Ответы [ 23 ]

0 голосов
/ 31 августа 2009

как расширение ответа SmileyChris, вы можете добавить поле datetime в модель для last_updated и установить какое-то ограничение на максимальный возраст, который вы дадите ему до проверки на изменение

0 голосов
/ 04 февраля 2019

Если вы не заинтересованы в переопределении метода save, вы можете сделать

  model_fields = [f.name for f in YourModel._meta.get_fields()]
  valid_data = {
        key: new_data[key]
        for key in model_fields
        if key in new_data.keys()
  }

  for (key, value) in valid_data.items():
        if getattr(instance, key) != value:
           print ('Data has changed')

        setattr(instance, key, value)

 instance.save()
0 голосов
/ 30 августа 2014

Миксин от @ivanlivski великолепен.

Я расширил его до

  • Убедитесь, что он работает с десятичными полями.
  • Выставлять свойства для упрощения использования

Обновленный код доступен здесь: https://github.com/sknutsonsf/python-contrib/blob/master/src/django/utils/ModelDiffMixin.py

Чтобы помочь новичкам в Python или Django, я приведу более полный пример. Это конкретное использование состоит в том, чтобы получить файл от поставщика данных и убедиться, что записи в базе данных отражают файл.

Моя модель объекта:

class Station(ModelDiffMixin.ModelDiffMixin, models.Model):
    station_name = models.CharField(max_length=200)
    nearby_city = models.CharField(max_length=200)

    precipitation = models.DecimalField(max_digits=5, decimal_places=2)
    # <list of many other fields>

   def is_float_changed (self,v1, v2):
        ''' Compare two floating values to just two digit precision
        Override Default precision is 5 digits
        '''
        return abs (round (v1 - v2, 2)) > 0.01

Класс, который загружает файл, имеет следующие методы:

class UpdateWeather (object)
    # other methods omitted

    def update_stations (self, filename):
        # read all existing data 
        all_stations = models.Station.objects.all()
        self._existing_stations = {}

        # insert into a collection for referencing while we check if data exists
        for stn in all_stations.iterator():
            self._existing_stations[stn.id] = stn

        # read the file. result is array of objects in known column order
        data = read_tabbed_file(filename)

        # iterate rows from file and insert or update where needed
        for rownum in range(sh.nrows):
            self._update_row(sh.row(rownum));

        # now anything remaining in the collection is no longer active
        # since it was not found in the newest file
        # for now, delete that record
        # there should never be any of these if the file was created properly
        for stn in self._existing_stations.values():
            stn.delete()
            self._num_deleted = self._num_deleted+1


    def _update_row (self, rowdata):
        stnid = int(rowdata[0].value) 
        name = rowdata[1].value.strip()

        # skip the blank names where data source has ids with no data today
        if len(name) < 1:
            return

        # fetch rest of fields and do sanity test
        nearby_city = rowdata[2].value.strip()
        precip = rowdata[3].value

        if stnid in self._existing_stations:
            stn = self._existing_stations[stnid]
            del self._existing_stations[stnid]
            is_update = True;
        else:
            stn = models.Station()
            is_update = False;

        # object is new or old, don't care here            
        stn.id = stnid
        stn.station_name = name;
        stn.nearby_city = nearby_city
        stn.precipitation = precip

        # many other fields updated from the file 

        if is_update == True:

            # we use a model mixin to simplify detection of changes
            # at the cost of extra memory to store the objects            
            if stn.has_changed == True:
                self._num_updated = self._num_updated + 1;
                stn.save();
        else:
            self._num_created = self._num_created + 1;
            stn.save()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...