Ticket #4102: 4102-dirty.4.patch
File 4102-dirty.4.patch, 4.9 KB (added by , 17 years ago) |
---|
-
django/db/models/base.py
94 94 def __ne__(self, other): 95 95 return not self.__eq__(other) 96 96 97 _dirty = {} 98 99 def __setattr__(self, name, value): 100 if name != '_dirty' and (not hasattr(self, name) or value != getattr(self, name)): 101 self._dirty[name] = True 102 super(Model, self).__setattr__(name, value) 103 104 def _wash(self): 105 self._dirty = {} 106 97 107 def __init__(self, *args, **kwargs): 98 108 dispatcher.send(signal=signals.pre_init, sender=self.__class__, args=args, kwargs=kwargs) 99 109 110 wash = kwargs.pop('wash', False) 111 dirty = {} 112 100 113 # There is a rather weird disparity here; if kwargs, it's set, then args 101 # overrides it. It should be one or the other; don't duplicate the work 114 # overrides it. It should be one or the other; don't duplicate the work. 102 115 # The reason for the kwargs check is that standard iterator passes in by 103 # args, and nstantiation for iteration is 33% faster.116 # args, and instantiation for iteration is 33% faster. 104 117 args_len = len(args) 105 118 if args_len > len(self._meta.fields): 106 119 # Daft, but matches old exception sans the err msg. … … 114 127 # without changing the logic. 115 128 for val, field in izip(args, fields_iter): 116 129 setattr(self, field.attname, val) 130 dirty[field.attname] = True 117 131 else: 118 132 # Slower, kwargs-ready version. 119 133 for val, field in izip(args, fields_iter): 120 134 setattr(self, field.attname, val) 135 dirty[field.attname] = True 121 136 kwargs.pop(field.name, None) 122 137 # Maintain compatibility with existing calls. 123 138 if isinstance(field.rel, ManyToOneRel): … … 164 179 pass 165 180 if kwargs: 166 181 raise TypeError, "'%s' is an invalid keyword argument for this function" % kwargs.keys()[0] 182 183 self._wash() 184 if not wash: 185 self._dirty = dirty 167 186 dispatcher.send(signal=signals.post_init, sender=self.__class__, instance=self) 168 187 169 188 def add_to_class(cls, name, value): … … 199 218 _prepare = classmethod(_prepare) 200 219 201 220 def save(self): 221 "Save model object to database, creating if doesn't exist, otherwise updating" 202 222 dispatcher.send(signal=signals.pre_save, sender=self.__class__, instance=self) 203 223 204 non_pks = [f for f in self._meta.fields if not f.primary_key] 224 non_pks = [f for f in self._meta.fields if not f.primary_key and (self._dirty.get(f.name, False) or self._dirty.get(f.attname, False))] 225 self._wash() 205 226 cursor = connection.cursor() 206 227 207 228 # First, try an UPDATE. If that doesn't update anything, do an INSERT. -
django/db/models/query.py
201 201 obj, index_end = get_cached_row(klass=self.model, row=row, 202 202 index_start=0, max_depth=self._max_related_depth) 203 203 else: 204 obj = self.model( *row[:index_end])204 obj = self.model(wash=True, *row[:index_end]) 205 205 for i, k in enumerate(extra_select): 206 206 setattr(obj, k[0], row[index_end+i]) 207 207 yield obj -
tests/modeltests/update_fields/models.py
1 """ 2 #. Save only modified fields on update 3 """ 4 from django.db import models 5 6 class Article(models.Model): 7 headline = models.CharField(maxlength=100, default='Default headline') 8 body = models.TextField() 9 pub_date = models.DateTimeField() 10 11 class Meta: 12 ordering = ('pub_date','headline') 13 14 def __str__(self): 15 return self.headline 16 17 __test__ = {'API_TESTS':""" 18 # Create a couple of Articles. 19 >>> from datetime import datetime 20 >>> a = Article(headline='Article 1', body='Body 1', pub_date=datetime(2007, 5, 5)) 21 >>> a.save() 22 23 # Change headline and body on different instances, then save both to verify 24 # that each only updated the modified field 25 >>> a1 = Article.objects.get(pk=a.id) 26 >>> a2 = Article.objects.get(pk=a.id) 27 >>> a1.headline = 'Changed article 1' 28 >>> a2.body = 'Changed body 1' 29 >>> a1.save() 30 >>> a2.save() 31 >>> a3 = Article.objects.get(pk=a.id) 32 >>> a3.headline 33 'Changed article 1' 34 >>> a3.body 35 'Changed body 1' 36 """}