Ticket #4102: #4102-update_modified_fields_only.diff

File #4102-update_modified_fields_only.diff, 4.3 KB (added by Kronuz, 4 years ago)

Fixes multitable inheritance

  • django/db/models/base.py

    4102_Django1.3_JL20110610.patch
     
    278278    def __init__(self, *args, **kwargs):
    279279        signals.pre_init.send(sender=self.__class__, args=args, kwargs=kwargs)
    280280
     281        self._reset_modified_attrs()
     282
    281283        # Set up the storage for instance state
    282284        self._state = ModelState()
    283285
     
    368370        super(Model, self).__init__()
    369371        signals.post_init.send(sender=self.__class__, instance=self)
    370372
     373    def __setattr__(self, name, value):
     374        if name not in self.__dict__.setdefault('_modified_attrs', []):
     375            if not hasattr(self, name) or value != getattr(self, name):
     376                self._modified_attrs.append(name)
     377        super(Model, self).__setattr__(name, value)
     378
     379    def _reset_modified_attrs(self):
     380        self.__dict__['_modified_attrs'] = []
     381
    371382    def __repr__(self):
    372383        try:
    373384            u = unicode(self)
     
    465476    save.alters_data = True
    466477
    467478    def save_base(self, raw=False, cls=None, origin=None, force_insert=False,
    468             force_update=False, using=None):
     479            force_update=False, using=None, modified_attrs=None):
    469480        """
    470481        Does the heavy-lifting involved in saving. Subclasses shouldn't need to
    471482        override this method. It's separate from save() in order to hide the
     
    486497        if origin and not meta.auto_created:
    487498            signals.pre_save.send(sender=origin, instance=self, raw=raw, using=using)
    488499
     500        if modified_attrs is None:
     501            modified_attrs = self._modified_attrs
     502
    489503        # If we are in a raw save, save the object exactly as presented.
    490504        # That means that we don't try to be smart about saving attributes
    491505        # that might have come from the parent class - we just save the
     
    504518                if field and getattr(self, parent._meta.pk.attname) is None and getattr(self, field.attname) is not None:
    505519                    setattr(self, parent._meta.pk.attname, getattr(self, field.attname))
    506520
    507                 self.save_base(cls=parent, origin=org, using=using)
     521                self.save_base(cls=parent, origin=org, using=using, modified_attrs=modified_attrs)
    508522
    509523                if field:
    510524                    setattr(self, field.attname, self._get_pk_val(parent._meta))
     
    526540                    # It does already exist, so do an UPDATE.
    527541                    if force_update or non_pks:
    528542                        values = [(f, None, (raw and getattr(self, f.attname) or f.pre_save(self, False))) for f in non_pks]
     543
     544                        # Only keep modified_attrs and those whose value has changed after pre_save
     545                        if self._state.db == using:
     546                            values = [v for v in values
     547                                      if v[0].name in modified_attrs
     548                                      or v[0].attname in modified_attrs
     549                                      or v[2] != getattr(self, v[0].name)]
    529550                        rows = manager.using(using).filter(pk=pk_val)._update(values)
    530551                        if force_update and not rows:
    531552                            raise DatabaseError("Forced update did not affect any rows.")
     
    562583                    setattr(self, meta.pk.attname, result)
    563584            transaction.commit_unless_managed(using=using)
    564585
     586            self._reset_modified_attrs()
     587
    565588        # Store the database on which the object was saved
    566589        self._state.db = using
    567590        # Once saved, this is no longer a to-be-added instance.
  • django/db/models/query.py

    class QuerySet(object): 
    284284                else:
    285285                    # Omit aggregates in object creation.
    286286                    obj = model(*row[index_start:aggregate_start])
     287                    # Models keep a track of modified attrs to choose which
     288                    # fields to save. Since we're just pulling from the
     289                    # database, nothing has changed yet.
     290                    obj._reset_modified_attrs()
    287291
    288292                # Store the source database of the object
    289293                obj._state.db = db
Back to Top