Ticket #4102: 4102-dirty-set.4.patch
File 4102-dirty-set.4.patch, 5.4 KB (added by , 17 years ago) |
---|
-
django/db/models/base.py
19 19 import sys 20 20 import os 21 21 22 try: 23 set 24 except NameError: 25 from sets import Set as set # Python 2.3 fallback 26 22 27 class ModelBase(type): 23 28 "Metaclass for all models" 24 29 def __new__(cls, name, bases, attrs): … … 97 102 def __ne__(self, other): 98 103 return not self.__eq__(other) 99 104 105 def __setattr__(self, name, value): 106 if hasattr(self, '_modified_fields') and name != '_modified_fields' and (not hasattr(self, name) or value != getattr(self, name)): 107 self._modified_fields.add(name) 108 super(Model, self).__setattr__(name, value) 109 110 def reset_modified_fields(self): 111 self._modified_fields = set() 112 100 113 def __init__(self, *args, **kwargs): 101 114 dispatcher.send(signal=signals.pre_init, sender=self.__class__, args=args, kwargs=kwargs) 102 115 116 modified_fields = set() 117 103 118 # There is a rather weird disparity here; if kwargs, it's set, then args 104 # overrides it. It should be one or the other; don't duplicate the work 119 # overrides it. It should be one or the other; don't duplicate the work. 105 120 # The reason for the kwargs check is that standard iterator passes in by 106 # args, and nstantiation for iteration is 33% faster.121 # args, and instantiation for iteration is 33% faster. 107 122 args_len = len(args) 108 123 if args_len > len(self._meta.fields): 109 124 # Daft, but matches old exception sans the err msg. … … 117 132 # without changing the logic. 118 133 for val, field in izip(args, fields_iter): 119 134 setattr(self, field.attname, val) 135 modified_fields.add(field.attname) 120 136 else: 121 137 # Slower, kwargs-ready version. 122 138 for val, field in izip(args, fields_iter): 123 139 setattr(self, field.attname, val) 140 modified_fields.add(field.attname) 124 141 kwargs.pop(field.name, None) 125 142 # Maintain compatibility with existing calls. 126 143 if isinstance(field.rel, ManyToOneRel): … … 130 147 # keywords, or default. 131 148 132 149 for field in fields_iter: 150 if field.attname in kwargs or field.name in kwargs: 151 modified_fields.add(field.attname) 133 152 if kwargs: 134 153 if isinstance(field.rel, ManyToOneRel): 135 154 try: … … 167 186 pass 168 187 if kwargs: 169 188 raise TypeError, "'%s' is an invalid keyword argument for this function" % kwargs.keys()[0] 189 190 self.reset_modified_fields() 191 self._modified_fields = modified_fields 170 192 dispatcher.send(signal=signals.post_init, sender=self.__class__, instance=self) 171 193 172 194 def add_to_class(cls, name, value): … … 202 224 _prepare = classmethod(_prepare) 203 225 204 226 def save(self, raw=False): 227 "Save model object to database, creating if doesn't exist, otherwise updating" 205 228 dispatcher.send(signal=signals.pre_save, sender=self.__class__, instance=self) 206 229 207 non_pks = [f for f in self._meta.fields if not f.primary_key] 230 non_pks = [f for f in self._meta.fields if not f.primary_key and (f.name in self._modified_fields or f.attname in self._modified_fields)] 231 self.reset_modified_fields() 208 232 cursor = connection.cursor() 209 233 210 234 # First, try an UPDATE. If that doesn't update anything, do an INSERT. -
django/db/models/query.py
203 203 index_start=0, max_depth=self._max_related_depth) 204 204 else: 205 205 obj = self.model(*row[:index_end]) 206 obj.reset_modified_fields() 206 207 for i, k in enumerate(extra_select): 207 208 setattr(obj, k[0], row[index_end+i]) 208 209 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 """}