Ticket #17332: 17332.diff
File 17332.diff, 14.4 KB (added by , 13 years ago) |
---|
-
django/db/models/base.py
diff --git a/django/db/models/base.py b/django/db/models/base.py index ebd67be..116a086 100644
a b import copy 2 2 import sys 3 3 from functools import update_wrapper 4 4 from itertools import izip 5 import warnings 5 6 6 7 import django.db.models.manager # Imported to register signal handler. 7 8 from django.conf import settings … … class ModelState(object): 271 272 # Necessary for correct validation of new instances of objects with explicit (non-auto) PKs. 272 273 # This impacts validation only; it has no effect on the actual save. 273 274 self.adding = True 275 self.old_pk_values = {} 276 277 def update(self, obj, using, adding=False, pk_fields=None): 278 if pk_fields is None: 279 pk_fields = obj._meta.pk_fields 280 self.db = using 281 self.adding = adding 282 for f in pk_fields: 283 self.old_pk_values[f.attname] = f.to_immutable_value(obj) 284 285 def clear(self): 286 self.db = None 287 self.adding = True 288 self.old_pk_values = {} 274 289 275 290 class Model(object): 276 291 __metaclass__ = ModelBase … … class Model(object): 429 444 return getattr(self, meta.pk.attname) 430 445 431 446 def _set_pk_val(self, value): 447 if value is None: 448 self._state.old_pk_values[self._meta.pk.attname] = None 432 449 return setattr(self, self._meta.pk.attname, value) 433 450 434 451 pk = property(_get_pk_val, _set_pk_val) … … class Model(object): 486 503 if origin and not meta.auto_created: 487 504 signals.pre_save.send(sender=origin, instance=self, raw=raw, using=using) 488 505 506 # Proxy-objects do not need saving. Skip to the parent objects. 507 if meta.proxy: 508 for parent, _ in meta.parents.items(): 509 self.save_base(cls=parent, origin=cls, using=using) 510 return 489 511 # If we are in a raw save, save the object exactly as presented. 490 512 # That means that we don't try to be smart about saving attributes 491 513 # that might have come from the parent class - we just save the 492 514 # attributes we have been given to the class we have been given. 493 # We also go through this process to defer the save of proxy objects 494 # to their actual underlying model. 495 if not raw or meta.proxy: 496 if meta.proxy: 497 org = cls 498 else: 499 org = None 515 if not raw: 500 516 for parent, field in meta.parents.items(): 501 517 # At this point, parent's primary key field may be unknown 502 518 # (for example, from administration form which doesn't fill … … class Model(object): 504 520 if field and getattr(self, parent._meta.pk.attname) is None and getattr(self, field.attname) is not None: 505 521 setattr(self, parent._meta.pk.attname, getattr(self, field.attname)) 506 522 507 self.save_base(cls=parent, origin= org, using=using)523 self.save_base(cls=parent, origin=None, using=using) 508 524 509 525 if field: 510 526 setattr(self, field.attname, self._get_pk_val(parent._meta)) 511 if meta.proxy:512 return513 514 if not meta.proxy:515 non_pks = [f for f in meta.local_fields if not f.primary_key]516 517 # First, try an UPDATE. If that doesn't update anything, do an INSERT.518 pk_val = self._get_pk_val(meta)519 pk_set = pk_val is not None520 record_exists = True521 manager = cls._base_manager522 if pk_set:523 # Determine whether a record with the primary key already exists.524 if (force_update or (not force_insert and525 manager.using(using).filter(pk=pk_val).exists())):526 # It does already exist, so do an UPDATE.527 if force_update or non_pks:528 values = [(f, None, (raw and getattr(self, f.attname) or f.pre_save(self, False))) for f in non_pks]529 if values:530 rows = manager.using(using).filter(pk=pk_val)._update(values)531 if force_update and not rows:532 raise DatabaseError("Forced update did not affect any rows.")533 else:534 record_exists = False535 if not pk_set or not record_exists:536 if meta.order_with_respect_to:537 # If this is a model with an order_with_respect_to538 # autopopulate the _order field539 field = meta.order_with_respect_to540 order_value = manager.using(using).filter(**{field.name: getattr(self, field.attname)}).count()541 self._order = order_value542 543 fields = meta.local_fields544 if not pk_set:545 if force_update:546 raise ValueError("Cannot force an update in save() with no primary key.")547 fields = [f for f in fields if not isinstance(f, AutoField)]548 527 528 non_pks = [f for f in meta.local_fields if not f.primary_key] 529 pk_val = self._get_pk_val(meta) 530 pk_set = pk_val is not None 531 record_exists = True 532 manager = cls._base_manager 533 534 if pk_set and not self._state.adding: 535 old_pk_val = self._state.old_pk_values[meta.pk.attname] 536 if old_pk_val is not None and pk_val != old_pk_val: 537 warnings.warn("Saving an object with changed primary key is deprecated. " 538 "You can use obj.pk = None; obj.pk = new_val to bypass this check.", 539 PendingDeprecationWarning) 540 541 # First, try an UPDATE. If that doesn't update anything, do an INSERT. 542 if pk_set: 543 # Determine whether a record with the primary key already exists. 544 if (force_update or (not force_insert and 545 manager.using(using).filter(pk=pk_val).exists())): 546 # It does already exist, so do an UPDATE. 547 if force_update or non_pks: 548 values = [(f, None, (raw and getattr(self, f.attname) or f.pre_save(self, False))) for f in non_pks] 549 if values: 550 rows = manager.using(using).filter(pk=pk_val)._update(values) 551 if force_update and not rows: 552 raise DatabaseError("Forced update did not affect any rows.") 553 else: 549 554 record_exists = False 550 551 update_pk = bool(meta.has_auto_field and not pk_set) 552 result = manager._insert([self], fields=fields, return_id=update_pk, using=using, raw=raw) 553 554 if update_pk: 555 setattr(self, meta.pk.attname, result) 555 if not pk_set or not record_exists: 556 if meta.order_with_respect_to: 557 # If this is a model with an order_with_respect_to 558 # autopopulate the _order field 559 field = meta.order_with_respect_to 560 order_value = manager.using(using).filter(**{field.name: getattr(self, field.attname)}).count() 561 self._order = order_value 562 563 fields = meta.local_fields 564 if not pk_set: 565 if force_update: 566 raise ValueError("Cannot force an update in save() with no primary key.") 567 fields = [f for f in fields if not isinstance(f, AutoField)] 568 569 record_exists = False 570 571 update_pk = bool(meta.has_auto_field and not pk_set) 572 result = manager._insert([self], fields=fields, return_id=update_pk, using=using, raw=raw) 573 574 if update_pk: 575 setattr(self, meta.pk.attname, result) 576 577 if origin: 578 # We are at the topmost object - finalize the save 556 579 transaction.commit_unless_managed(using=using) 557 558 # Store the database on which the object was saved 559 self._state.db = using 560 # Once saved, this is no longer a to-be-added instance. 561 self._state.adding = False 562 563 # Signal that the save is complete 564 if origin and not meta.auto_created: 565 signals.post_save.send(sender=origin, instance=self, 566 created=(not record_exists), raw=raw, using=using) 567 580 self._state.update(self, using) 581 if not meta.auto_created: 582 # Signal that the save is complete 583 signals.post_save.send(sender=origin, instance=self, 584 created=(not record_exists), raw=raw, using=using) 568 585 569 586 save_base.alters_data = True 570 587 … … class Model(object): 575 592 collector = Collector(using=using) 576 593 collector.collect([self]) 577 594 collector.delete() 595 self._state.clear() 578 596 579 597 delete.alters_data = True 580 598 -
django/db/models/fields/__init__.py
diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index 04b13aa..1c6d796 100644
a b class Field(object): 428 428 """ 429 429 return smart_unicode(self._get_val_from_obj(obj)) 430 430 431 def to_immutable_value(self, obj): 432 """ 433 Returns a value which is guaranteed to be immutable. This is used to 434 track changes in field values. The returned value should be usable in 435 database lookups. 436 """ 437 return getattr(obj, self.attname) 438 431 439 def bind(self, fieldmapping, original, bound_field_class): 432 440 return bound_field_class(self, fieldmapping, original) 433 441 -
django/db/models/fields/files.py
diff --git a/django/db/models/fields/files.py b/django/db/models/fields/files.py index d4b1743..211d05a 100644
a b class FileField(Field): 249 249 file.save(file.name, file, save=False) 250 250 return file 251 251 252 def to_immutable_value(self, obj): 253 return getattr(obj, self.attname).name 254 252 255 def contribute_to_class(self, cls, name): 253 256 super(FileField, self).contribute_to_class(cls, name) 254 257 setattr(cls, self.name, self.descriptor_class(self)) -
django/db/models/options.py
diff --git a/django/db/models/options.py b/django/db/models/options.py index 0cd52a3..af33e62 100644
a b class Options(object): 35 35 self.db_tablespace = settings.DEFAULT_TABLESPACE 36 36 self.admin = None 37 37 self.meta = meta 38 # The PK of the model's table 38 39 self.pk = None 39 40 self.has_auto_field, self.auto_field = False, None 40 41 self.abstract = False … … class Options(object): 105 106 self.db_table = "%s_%s" % (self.app_label, self.module_name) 106 107 self.db_table = truncate_name(self.db_table, connection.ops.max_name_length()) 107 108 109 108 110 def _prepare(self, model): 109 111 if self.order_with_respect_to: 110 112 self.order_with_respect_to = self.get_field(self.order_with_respect_to) … … class Options(object): 164 166 if hasattr(self, '_field_cache'): 165 167 del self._field_cache 166 168 del self._field_name_cache 169 del self._pk_field_cache 167 170 168 171 if hasattr(self, '_name_map'): 169 172 del self._name_map … … class Options(object): 219 222 return self._field_name_cache 220 223 fields = property(_fields) 221 224 225 def _pk_fields(self): 226 """ 227 All the PKs the model has, including parent tables. 228 """ 229 try: 230 self._field_name_cache 231 except AttributeError: 232 self._fill_fields_cache() 233 return self._pk_field_cache 234 pk_fields = property(_pk_fields) 235 222 236 def get_fields_with_model(self): 223 237 """ 224 238 Returns a sequence of (field, model) pairs for all fields. The "model" … … class Options(object): 242 256 cache.extend([(f, None) for f in self.local_fields]) 243 257 self._field_cache = tuple(cache) 244 258 self._field_name_cache = [x for x, _ in cache] 259 self._pk_field_cache = tuple(x for x, _ in cache if x.primary_key) 245 260 246 261 def _many_to_many(self): 247 262 try: -
django/db/models/query.py
diff --git a/django/db/models/query.py b/django/db/models/query.py index 80cdefd..10a5527 100644
a b class QuerySet(object): 278 278 init_list.append(field.attname) 279 279 model_cls = deferred_class_factory(self.model, skip) 280 280 281 # Cache db and modeloutside the loop281 # Cache some values outside the loop 282 282 db = self.db 283 283 model = self.model 284 284 compiler = self.query.get_compiler(using=db) 285 pk_fields = model._meta.pk_fields 285 286 if fill_cache: 286 287 klass_info = get_klass_info(model, max_depth=max_depth, 287 288 requested=requested, only_load=only_load) … … class QuerySet(object): 297 298 # Omit aggregates in object creation. 298 299 obj = model(*row[index_start:aggregate_start]) 299 300 300 # Store the source database of the object 301 obj._state.db = db 302 # This object came from the database; it's not being added. 303 obj._state.adding = False 301 obj._state.update(obj, db, pk_fields=pk_fields) 304 302 305 303 if extra_select: 306 304 for i, k in enumerate(extra_select): … … def get_klass_info(klass, max_depth=0, cur_depth=0, requested=None, 1316 1314 return klass, field_names, field_count, related_fields, reverse_related_fields 1317 1315 1318 1316 1319 def get_cached_row(row, index_start, using, 1317 def get_cached_row(row, index_start, using, klass_info, offset=0): 1320 1318 """ 1321 1319 Helper function that recursively returns an object with the specified 1322 1320 related attributes already populated. … … def get_cached_row(row, index_start, using, klass_info, offset=0): 1352 1350 1353 1351 # If an object was retrieved, set the database state. 1354 1352 if obj: 1355 obj._state.db = using 1356 obj._state.adding = False 1353 obj._state.update(obj, using) 1357 1354 1358 1355 # Instantiate related fields 1359 1356 index_end = index_start + field_count + offset … … class RawQuerySet(object): 1486 1483 for column, pos in annotation_fields: 1487 1484 setattr(instance, column, values[pos]) 1488 1485 1489 instance._state.db = db 1490 instance._state.adding = False 1491 1486 instance._state.update(instance, db) 1492 1487 yield instance 1493 1488 1494 1489 def __repr__(self):