diff --git a/django/core/serializers/base.py b/django/core/serializers/base.py
index 190636e..9f535e3 100644
--- a/django/core/serializers/base.py
+++ b/django/core/serializers/base.py
@@ -170,3 +170,21 @@ class DeserializedObject(object):
         # prevent a second (possibly accidental) call to save() from saving
         # the m2m data twice.
         self.m2m_data = None
+
+def build_instance(Model, data, db):
+    """
+    Build a model instance.
+
+    If the model instance doesn't have a primary key and the model supports
+    natural keys, try to retrieve it from the database.
+    """
+    obj = Model(**data)
+    if obj.pk is None and hasattr(Model, 'natural_key') and\
+            hasattr(Model._default_manager, 'get_by_natural_key'):
+        pk = obj.natural_key()
+        try:
+            obj.pk = Model._default_manager.db_manager(db)\
+                                           .get_by_natural_key(*pk).pk
+        except Model.DoesNotExist:
+            pass
+    return obj
diff --git a/django/core/serializers/python.py b/django/core/serializers/python.py
index a68ea21..e557008 100644
--- a/django/core/serializers/python.py
+++ b/django/core/serializers/python.py
@@ -27,11 +27,13 @@ class Serializer(base.Serializer):
         self._current = {}
 
     def end_object(self, obj):
-        self.objects.append({
-            "model"  : smart_unicode(obj._meta),
-            "pk"     : smart_unicode(obj._get_pk_val(), strings_only=True),
-            "fields" : self._current
-        })
+        data = {
+            "model": smart_unicode(obj._meta),
+            "fields": self._current
+        }
+        if not self.use_natural_keys or not hasattr(obj, 'natural_key'):
+            data['pk'] = smart_unicode(obj._get_pk_val(), strings_only=True)
+        self.objects.append(data)
         self._current = None
 
     def handle_field(self, obj, field):
@@ -82,7 +84,9 @@ def Deserializer(object_list, **options):
     for d in object_list:
         # Look up the model and starting build a dict of data for it.
         Model = _get_model(d["model"])
-        data = {Model._meta.pk.attname : Model._meta.pk.to_python(d["pk"])}
+        data = {}
+        if 'pk' in d:
+            data[Model._meta.pk.attname] = d['pk']
         m2m_data = {}
 
         # Handle each field
@@ -127,7 +131,9 @@ def Deserializer(object_list, **options):
             else:
                 data[field.name] = field.to_python(field_value)
 
-        yield base.DeserializedObject(Model(**data), m2m_data)
+        obj = base.build_instance(Model, data, db)
+
+        yield base.DeserializedObject(obj, m2m_data)
 
 def _get_model(model_identifier):
     """
diff --git a/django/core/serializers/xml_serializer.py b/django/core/serializers/xml_serializer.py
index 5fef3b6..a7d5218 100644
--- a/django/core/serializers/xml_serializer.py
+++ b/django/core/serializers/xml_serializer.py
@@ -42,10 +42,10 @@ class Serializer(base.Serializer):
             raise base.SerializationError("Non-model object (%s) encountered during serialization" % type(obj))
 
         self.indent(1)
-        self.xml.startElement("object", {
-            "pk"    : smart_unicode(obj._get_pk_val()),
-            "model" : smart_unicode(obj._meta),
-        })
+        object_data = {"model": smart_unicode(obj._meta)}
+        if not self.use_natural_keys or not hasattr(obj, 'natural_key'):
+            object_data['pk'] = smart_unicode(obj._get_pk_val())
+        self.xml.startElement("object", object_data)
 
     def end_object(self, obj):
         """
@@ -166,13 +166,11 @@ class Deserializer(base.Deserializer):
         # bail.
         Model = self._get_model_from_node(node, "model")
 
-        # Start building a data dictionary from the object.  If the node is
-        # missing the pk attribute, bail.
-        pk = node.getAttribute("pk")
-        if not pk:
-            raise base.DeserializationError("<object> node is missing the 'pk' attribute")
-
-        data = {Model._meta.pk.attname : Model._meta.pk.to_python(pk)}
+        # Start building a data dictionary from the object.
+        data = {}
+        if node.hasAttribute('pk'):
+            pk = node.getAttribute("pk")
+            data[Model._meta.pk.attname] = node.Model._meta.pk.to_python(pk)
 
         # Also start building a dict of m2m data (this is saved as
         # {m2m_accessor_attribute : [list_of_related_objects]})
@@ -203,8 +201,10 @@ class Deserializer(base.Deserializer):
                     value = field.to_python(getInnerText(field_node).strip())
                 data[field.name] = value
 
+        obj = base.build_instance(Model, data, self.db)
+
         # Return a DeserializedObject so that the m2m data has a place to live.
-        return base.DeserializedObject(Model(**data), m2m_data)
+        return base.DeserializedObject(obj, m2m_data)
 
     def _handle_fk_field_node(self, node, field):
         """
