diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py
index 01144eb..2e24f73 100644
--- a/django/db/backends/__init__.py
+++ b/django/db/backends/__init__.py
@@ -281,6 +281,7 @@ class BaseDatabaseFeatures(object):
     allow_sliced_subqueries = True
 
     supports_joins = True
+    distinguishes_insert_from_update = True
     supports_select_related = True
 
     # 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/django/db/models/base.py
+++ b/django/db/models/base.py
@@ -273,6 +273,7 @@ class Model(object):
     _deferred = False
 
     def __init__(self, *args, **kwargs):
+        self._entity_exists = kwargs.pop('__entity_exists', False)
         signals.pre_init.send(sender=self.__class__, args=args, kwargs=kwargs)
 
         # Set up the storage for instance state
@@ -362,6 +363,7 @@ class Model(object):
                     pass
             if kwargs:
                 raise TypeError("'%s' is an invalid keyword argument for this function" % kwargs.keys()[0])
+        self._original_pk = self.pk if self._meta.pk is not None else None
         super(Model, self).__init__()
         signals.post_init.send(sender=self.__class__, instance=self)
 
@@ -470,6 +472,7 @@ class Model(object):
         ('raw', 'cls', and 'origin').
         """
         using = using or router.db_for_write(self.__class__, instance=self)
+        entity_exists = bool(self._entity_exists and self._original_pk == self.pk)
         connection = connections[using]
         assert not (force_insert and force_update)
         if cls is None:
@@ -516,7 +519,19 @@ class Model(object):
             pk_set = pk_val is not None
             record_exists = True
             manager = cls._base_manager
-            if pk_set:
+            # TODO/NONREL: Some backends could emulate force_insert/_update
+            # with an optimistic transaction, but since it's costly we should
+            # only do it when the user explicitly wants it.
+            # By adding support for an optimistic locking transaction
+            # in Django (SQL: SELECT ... FOR UPDATE) we could even make that
+            # part fully reusable on all backends (the current .exists()
+            # check below isn't really safe if you have lots of concurrent
+            # requests. BTW, and neither is QuerySet.get_or_create).
+            try_update = connection.features.distinguishes_insert_from_update
+            if not try_update:
+                record_exists = False
+
+            if try_update and pk_set:
                 # Determine whether a record with the primary key already exists.
                 if (force_update or (not force_insert and
                         manager.using(using).filter(pk=pk_val).exists())):
@@ -536,13 +551,18 @@ class Model(object):
                     order_value = manager.using(using).filter(**{field.name: getattr(self, field.attname)}).count()
                     self._order = order_value
 
+                if connection.features.distinguishes_insert_from_update:
+                    add = True
+                else:
+                    add = not entity_exists
+
                 if not pk_set:
                     if force_update:
                         raise ValueError("Cannot force an update in save() with no primary key.")
-                    values = [(f, f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True), connection=connection))
+                    values = [(f, f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, add), connection=connection))
                         for f in meta.local_fields if not isinstance(f, AutoField)]
                 else:
-                    values = [(f, f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True), connection=connection))
+                    values = [(f, f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, add), connection=connection))
                         for f in meta.local_fields]
 
                 record_exists = False
@@ -566,8 +586,15 @@ class Model(object):
 
         # Signal that the save is complete
         if origin and not meta.auto_created:
+            if connection.features.distinguishes_insert_from_update:
+                created = not record_exists
+            else:
+                created = not entity_exists
             signals.post_save.send(sender=origin, instance=self,
-                created=(not record_exists), raw=raw, using=using)
+                created=created, raw=raw, using=using)
+
+        self._entity_exists = True
+        self._original_pk = self.pk
 
 
     save_base.alters_data = True
@@ -580,6 +607,9 @@ class Model(object):
         collector.collect([self])
         collector.delete()
 
+        self._entity_exists = False
+        self._original_pk = None
+
     delete.alters_data = True
 
     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/django/db/models/query.py
+++ b/django/db/models/query.py
@@ -282,10 +282,10 @@ class QuerySet(object):
                 if skip:
                     row_data = row[index_start:aggregate_start]
                     pk_val = row_data[pk_idx]
-                    obj = model_cls(**dict(zip(init_list, row_data)))
+                    obj = model_cls(**dict(zip(init_list, row_data), __entity_exists=True))
                 else:
                     # Omit aggregates in object creation.
-                    obj = model(*row[index_start:aggregate_start])
+                    obj = model(*row[index_start:aggregate_start], **{'__entity_exists': True})
 
                 # Store the source database of the object
                 obj._state.db = db
@@ -1197,9 +1197,9 @@ def get_cached_row(klass, row, index_start, using, max_depth=0, cur_depth=0,
             obj = None
         elif skip:
             klass = deferred_class_factory(klass, skip)
-            obj = klass(**dict(zip(init_list, fields)))
+            obj = klass(__entity_exists=True, **dict(zip(init_list, fields)))
         else:
-            obj = klass(*fields)
+            obj = klass(*fields, **{'__entity_exists': True})
 
     else:
         # Load all fields on klass
@@ -1215,7 +1215,7 @@ def get_cached_row(klass, row, index_start, using, max_depth=0, cur_depth=0,
         if fields == (None,) * field_count:
             obj = None
         else:
-            obj = klass(**dict(zip(field_names, fields)))
+            obj = klass(__entity_exists=True, **dict(zip(field_names, fields)))
 
     # If an object was retrieved, set the database state.
     if obj:
