diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py
index 01144eb..2e24f73 100644
a
|
b
|
class BaseDatabaseFeatures(object):
|
281 | 281 | allow_sliced_subqueries = True |
282 | 282 | |
283 | 283 | supports_joins = True |
| 284 | distinguishes_insert_from_update = True |
284 | 285 | supports_select_related = True |
285 | 286 | |
286 | 287 | # Does the default test database allow multiple connections? |
diff --git a/django/db/models/base.py b/django/db/models/base.py
index 286f9b0..c0238b6 100644
a
|
b
|
class Model(object):
|
273 | 273 | _deferred = False |
274 | 274 | |
275 | 275 | def __init__(self, *args, **kwargs): |
| 276 | self._entity_exists = kwargs.pop('__entity_exists', False) |
276 | 277 | signals.pre_init.send(sender=self.__class__, args=args, kwargs=kwargs) |
277 | 278 | |
278 | 279 | # Set up the storage for instance state |
… |
… |
class Model(object):
|
362 | 363 | pass |
363 | 364 | if kwargs: |
364 | 365 | raise TypeError("'%s' is an invalid keyword argument for this function" % kwargs.keys()[0]) |
| 366 | self._original_pk = self.pk if self._meta.pk is not None else None |
365 | 367 | super(Model, self).__init__() |
366 | 368 | signals.post_init.send(sender=self.__class__, instance=self) |
367 | 369 | |
… |
… |
class Model(object):
|
470 | 472 | ('raw', 'cls', and 'origin'). |
471 | 473 | """ |
472 | 474 | using = using or router.db_for_write(self.__class__, instance=self) |
| 475 | entity_exists = bool(self._entity_exists and self._original_pk == self.pk) |
473 | 476 | connection = connections[using] |
474 | 477 | assert not (force_insert and force_update) |
475 | 478 | if cls is None: |
… |
… |
class Model(object):
|
516 | 519 | pk_set = pk_val is not None |
517 | 520 | record_exists = True |
518 | 521 | manager = cls._base_manager |
519 | | if pk_set: |
| 522 | # TODO/NONREL: Some backends could emulate force_insert/_update |
| 523 | # with an optimistic transaction, but since it's costly we should |
| 524 | # only do it when the user explicitly wants it. |
| 525 | # By adding support for an optimistic locking transaction |
| 526 | # in Django (SQL: SELECT ... FOR UPDATE) we could even make that |
| 527 | # part fully reusable on all backends (the current .exists() |
| 528 | # check below isn't really safe if you have lots of concurrent |
| 529 | # requests. BTW, and neither is QuerySet.get_or_create). |
| 530 | try_update = connection.features.distinguishes_insert_from_update |
| 531 | if not try_update: |
| 532 | record_exists = False |
| 533 | |
| 534 | if try_update and pk_set: |
520 | 535 | # Determine whether a record with the primary key already exists. |
521 | 536 | if (force_update or (not force_insert and |
522 | 537 | manager.using(using).filter(pk=pk_val).exists())): |
… |
… |
class Model(object):
|
536 | 551 | order_value = manager.using(using).filter(**{field.name: getattr(self, field.attname)}).count() |
537 | 552 | self._order = order_value |
538 | 553 | |
| 554 | if connection.features.distinguishes_insert_from_update: |
| 555 | add = True |
| 556 | else: |
| 557 | add = not entity_exists |
| 558 | |
539 | 559 | if not pk_set: |
540 | 560 | if force_update: |
541 | 561 | raise ValueError("Cannot force an update in save() with no primary key.") |
542 | | values = [(f, f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True), connection=connection)) |
| 562 | values = [(f, f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, add), connection=connection)) |
543 | 563 | for f in meta.local_fields if not isinstance(f, AutoField)] |
544 | 564 | else: |
545 | | values = [(f, f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True), connection=connection)) |
| 565 | values = [(f, f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, add), connection=connection)) |
546 | 566 | for f in meta.local_fields] |
547 | 567 | |
548 | 568 | record_exists = False |
… |
… |
class Model(object):
|
566 | 586 | |
567 | 587 | # Signal that the save is complete |
568 | 588 | if origin and not meta.auto_created: |
| 589 | if connection.features.distinguishes_insert_from_update: |
| 590 | created = not record_exists |
| 591 | else: |
| 592 | created = not entity_exists |
569 | 593 | signals.post_save.send(sender=origin, instance=self, |
570 | | created=(not record_exists), raw=raw, using=using) |
| 594 | created=created, raw=raw, using=using) |
| 595 | |
| 596 | self._entity_exists = True |
| 597 | self._original_pk = self.pk |
571 | 598 | |
572 | 599 | |
573 | 600 | save_base.alters_data = True |
… |
… |
class Model(object):
|
580 | 607 | collector.collect([self]) |
581 | 608 | collector.delete() |
582 | 609 | |
| 610 | self._entity_exists = False |
| 611 | self._original_pk = None |
| 612 | |
583 | 613 | delete.alters_data = True |
584 | 614 | |
585 | 615 | def _get_FIELD_display(self, field): |
diff --git a/django/db/models/query.py b/django/db/models/query.py
index 26402ba..7a9bb45 100644
a
|
b
|
class QuerySet(object):
|
282 | 282 | if skip: |
283 | 283 | row_data = row[index_start:aggregate_start] |
284 | 284 | pk_val = row_data[pk_idx] |
285 | | obj = model_cls(**dict(zip(init_list, row_data))) |
| 285 | obj = model_cls(**dict(zip(init_list, row_data), __entity_exists=True)) |
286 | 286 | else: |
287 | 287 | # Omit aggregates in object creation. |
288 | | obj = model(*row[index_start:aggregate_start]) |
| 288 | obj = model(*row[index_start:aggregate_start], **{'__entity_exists': True}) |
289 | 289 | |
290 | 290 | # Store the source database of the object |
291 | 291 | obj._state.db = db |
… |
… |
def get_cached_row(klass, row, index_start, using, max_depth=0, cur_depth=0,
|
1197 | 1197 | obj = None |
1198 | 1198 | elif skip: |
1199 | 1199 | klass = deferred_class_factory(klass, skip) |
1200 | | obj = klass(**dict(zip(init_list, fields))) |
| 1200 | obj = klass(__entity_exists=True, **dict(zip(init_list, fields))) |
1201 | 1201 | else: |
1202 | | obj = klass(*fields) |
| 1202 | obj = klass(*fields, **{'__entity_exists': True}) |
1203 | 1203 | |
1204 | 1204 | else: |
1205 | 1205 | # Load all fields on klass |
… |
… |
def get_cached_row(klass, row, index_start, using, max_depth=0, cur_depth=0,
|
1215 | 1215 | if fields == (None,) * field_count: |
1216 | 1216 | obj = None |
1217 | 1217 | else: |
1218 | | obj = klass(**dict(zip(field_names, fields))) |
| 1218 | obj = klass(__entity_exists=True, **dict(zip(field_names, fields))) |
1219 | 1219 | |
1220 | 1220 | # If an object was retrieved, set the database state. |
1221 | 1221 | if obj: |