diff --git a/django/db/models/base.py b/django/db/models/base.py
index b5ce39e..daa96d3 100644
--- a/django/db/models/base.py
+++ b/django/db/models/base.py
@@ -287,85 +287,89 @@ class Model(object):
         # The reason for the kwargs check is that standard iterator passes in by
         # args, and instantiation for iteration is 33% faster.
         args_len = len(args)
-        if args_len > len(self._meta.fields):
-            # Daft, but matches old exception sans the err msg.
-            raise IndexError("Number of args exceeds number of fields")
-
-        fields_iter = iter(self._meta.fields)
-        if not kwargs:
-            # The ordering of the izip calls matter - izip throws StopIteration
-            # when an iter throws it. So if the first iter throws it, the second
-            # is *not* consumed. We rely on this, so don't change the order
-            # without changing the logic.
-            for val, field in izip(args, fields_iter):
-                setattr(self, field.attname, val)
+
+        # Deferred models have a different set of init fields - this can return
+        # different set of attnames than the attnames of all the fields in the
+        # model.
+        init_attnames = self._meta.get_init_attnames()
+        # This is the common case - the case we have when loading from the DB
+        # Make it fast by special casing.
+        if args_len == len(init_attnames):
+            [setattr(self, attname, val) for val, attname 
+                 in izip(args, init_attnames)]
         else:
-            # Slower, kwargs-ready version.
-            for val, field in izip(args, fields_iter):
-                setattr(self, field.attname, val)
-                kwargs.pop(field.name, None)
-                # Maintain compatibility with existing calls.
-                if isinstance(field.rel, ManyToOneRel):
-                    kwargs.pop(field.attname, None)
-
-        # Now we're left with the unprocessed fields that *must* come from
-        # keywords, or default.
-
-        for field in fields_iter:
-            is_related_object = False
-            # This slightly odd construct is so that we can access any
-            # data-descriptor object (DeferredAttribute) without triggering its
-            # __get__ method.
-            if (field.attname not in kwargs and
-                    isinstance(self.__class__.__dict__.get(field.attname), DeferredAttribute)):
-                # This field will be populated on request.
-                continue
-            if kwargs:
-                if isinstance(field.rel, ManyToOneRel):
-                    try:
-                        # Assume object instance was passed in.
-                        rel_obj = kwargs.pop(field.name)
-                        is_related_object = True
-                    except KeyError:
+            if args_len > len(self._meta.fields):
+                # Daft, but matches old exception sans the err msg.
+                raise IndexError("Number of args exceeds number of fields")
+
+            fields_iter = iter(self._meta.fields)
+            if not kwargs:
+                # The ordering of the izip calls matter - izip throws StopIteration
+                # when an iter throws it. So if the first iter throws it, the second
+                # is *not* consumed. We rely on this, so don't change the order
+                # without changing the logic.
+                for val, field in izip(args, fields_iter):
+                    setattr(self, field.attname, val)
+            else:
+                # Slower, kwargs-ready version.
+                for val, field in izip(args, fields_iter):
+                    setattr(self, field.attname, val)
+                    kwargs.pop(field.name, None)
+                    # Maintain compatibility with existing calls.
+                    if isinstance(field.rel, ManyToOneRel):
+                        kwargs.pop(field.attname, None)
+ 
+            # Now we're left with the unprocessed fields that *must* come from
+            # keywords, or default.
+
+            for field in fields_iter:
+                is_related_object = False
+                if kwargs:
+                    if isinstance(field.rel, ManyToOneRel):
+                        try:
+                            # Assume object instance was passed in.
+                            rel_obj = kwargs.pop(field.name)
+                            is_related_object = True
+                        except KeyError:
+                            try:
+                                # Object instance wasn't passed in -- must be an ID.
+                                val = kwargs.pop(field.attname)
+                            except KeyError:
+                                val = field.get_default()
+                        else:
+                            # Object instance was passed in. Special case: You can
+                            # pass in "None" for related objects if it's allowed.
+                            if rel_obj is None and field.null:
+                                val = None
+                    else:
                         try:
-                            # Object instance wasn't passed in -- must be an ID.
                             val = kwargs.pop(field.attname)
                         except KeyError:
+                            # This is done with an exception rather than the
+                            # default argument on pop because we don't want
+                            # get_default() to be evaluated, and then not used.
+                            # Refs #12057.
                             val = field.get_default()
-                    else:
-                        # Object instance was passed in. Special case: You can
-                        # pass in "None" for related objects if it's allowed.
-                        if rel_obj is None and field.null:
-                            val = None
                 else:
-                    try:
-                        val = kwargs.pop(field.attname)
-                    except KeyError:
-                        # This is done with an exception rather than the
-                        # default argument on pop because we don't want
-                        # get_default() to be evaluated, and then not used.
-                        # Refs #12057.
-                        val = field.get_default()
-            else:
-                val = field.get_default()
-            if is_related_object:
-                # If we are passed a related instance, set it using the
-                # field.name instead of field.attname (e.g. "user" instead of
-                # "user_id") so that the object gets properly cached (and type
-                # checked) by the RelatedObjectDescriptor.
-                setattr(self, field.name, rel_obj)
-            else:
-                setattr(self, field.attname, val)
-
-        if kwargs:
-            for prop in kwargs.keys():
-                try:
-                    if isinstance(getattr(self.__class__, prop), property):
-                        setattr(self, prop, kwargs.pop(prop))
-                except AttributeError:
-                    pass
+                    val = field.get_default()
+                if is_related_object:
+                    # If we are passed a related instance, set it using the
+                    # field.name instead of field.attname (e.g. "user" instead of
+                    # "user_id") so that the object gets properly cached (and type
+                    # checked) by the RelatedObjectDescriptor.
+                    setattr(self, field.name, rel_obj)
+                else:
+                    setattr(self, field.attname, val)
+
             if kwargs:
-                raise TypeError("'%s' is an invalid keyword argument for this function" % kwargs.keys()[0])
+                for prop in kwargs.keys():
+                    try:
+                        if isinstance(getattr(self.__class__, prop), property):
+                            setattr(self, prop, kwargs.pop(prop))
+                    except AttributeError:
+                        pass
+                if kwargs:
+                    raise TypeError("'%s' is an invalid keyword argument for this function" % kwargs.keys()[0])
         super(Model, self).__init__()
         signals.post_init.send(sender=self.__class__, instance=self)
 
diff --git a/django/db/models/loading.py b/django/db/models/loading.py
index c344686..44ff2f3 100644
--- a/django/db/models/loading.py
+++ b/django/db/models/loading.py
@@ -213,7 +213,7 @@ class AppCache(object):
             self._populate()
         if only_installed and app_label not in self.app_labels:
             return None
-        return self.app_models.get(app_label, SortedDict()).get(model_name.lower())
+        return self.app_models.get(app_label, {}).get(model_name.lower())
 
     def register_models(self, app_label, *models):
         """
diff --git a/django/db/models/options.py b/django/db/models/options.py
index 0cd52a3..82b7f6a 100644
--- a/django/db/models/options.py
+++ b/django/db/models/options.py
@@ -44,6 +44,9 @@ class Options(object):
         self.parents = SortedDict()
         self.duplicate_targets = {}
         self.auto_created = False
+        # Deferred models want to use only a portion of all the fields.
+        # This is a list of fields.attnames we want to load.
+        self.only_load = []
 
         # To handle various inheritance situations, we need to track where
         # managers came from (concrete or abstract base classes).
@@ -105,6 +108,8 @@ class Options(object):
             self.db_table = "%s_%s" % (self.app_label, self.module_name)
             self.db_table = truncate_name(self.db_table, connection.ops.max_name_length())
 
+         
+
     def _prepare(self, model):
         if self.order_with_respect_to:
             self.order_with_respect_to = self.get_field(self.order_with_respect_to)
@@ -164,6 +169,7 @@ class Options(object):
             if hasattr(self, '_field_cache'):
                 del self._field_cache
                 del self._field_name_cache
+                del self._init_attname_cache
 
         if hasattr(self, '_name_map'):
             del self._name_map
@@ -231,6 +237,18 @@ class Options(object):
             self._fill_fields_cache()
         return self._field_cache
 
+    def get_init_attnames(self):
+        """
+        Returns a sequence of attribute names for model initialization. Note
+        that for deferred models this list contains just the loaded field
+        attribute names, not all of the model's attnames.
+        """
+        try:
+            self._init_attname_cache
+        except AttributeError:
+            self._fill_fields_cache()
+        return self._init_attname_cache
+    
     def _fill_fields_cache(self):
         cache = []
         for parent in self.parents:
@@ -242,6 +260,26 @@ class Options(object):
         cache.extend([(f, None) for f in self.local_fields])
         self._field_cache = tuple(cache)
         self._field_name_cache = [x for x, _ in cache]
+        if self.only_load:
+            self._init_attname_cache = tuple(
+                [x.attname for x, _ in cache 
+                 if x.attname in self.only_load]
+            )
+        else:
+            self._init_attname_cache = tuple([x.attname for x, _ in cache])
+
+    def set_loaded_fields(self, defer):
+        """
+        Deferred model class creation will call this method. This will set
+        the deferred_fields list and then delete the _init_attname_cache.
+        Next access to get_init_fields() will reload that cache.
+        """
+        # Due to some strange things in select_related query.py iterator
+        # we can be called with a list of defer fields which can be either
+        # attnames or or field names. TODO: Fix this (in query.py)
+        self.only_load = [f.attname for f in self.fields
+                          if f.name not in defer and f.attname not in defer]
+        del self._init_attname_cache
 
     def _many_to_many(self):
         try:
diff --git a/django/db/models/query.py b/django/db/models/query.py
index be42d02..83dedd4 100644
--- a/django/db/models/query.py
+++ b/django/db/models/query.py
@@ -265,37 +265,29 @@ class QuerySet(object):
         index_start = len(extra_select)
         aggregate_start = index_start + len(load_fields or self.model._meta.fields)
 
-        skip = None
         if load_fields and not fill_cache:
             # Some fields have been deferred, so we have to initialise
             # via keyword arguments.
             skip = set()
-            init_list = []
             for field in fields:
                 if field.name not in load_fields:
                     skip.add(field.attname)
-                else:
-                    init_list.append(field.attname)
             model_cls = deferred_class_factory(self.model, skip)
-
+        else:
+            model_cls = self.model
         # Cache db and model outside the loop
         db = self.db
-        model = self.model
         compiler = self.query.get_compiler(using=db)
         if fill_cache:
-            klass_info = get_klass_info(model, max_depth=max_depth,
+            klass_info = get_klass_info(self.model, max_depth=max_depth,
                                         requested=requested, only_load=only_load)
         for row in compiler.results_iter():
             if fill_cache:
                 obj, _ = get_cached_row(row, index_start, db, klass_info,
                                         offset=len(aggregate_select))
             else:
-                if skip:
-                    row_data = row[index_start:aggregate_start]
-                    obj = model_cls(**dict(zip(init_list, row_data)))
-                else:
-                    # Omit aggregates in object creation.
-                    obj = model(*row[index_start:aggregate_start])
+                # Omit aggregates in object creation.
+                obj = model_cls(*row[index_start:aggregate_start])
 
                 # Store the source database of the object
                 obj._state.db = db
@@ -1257,6 +1249,8 @@ def get_klass_info(klass, max_depth=0, cur_depth=0, requested=None,
     else:
         load_fields = None
 
+    # TODO - Due to removal of special handling of deferred model's __init__
+    # we could probably do some cleanup here.
     if load_fields:
         # Handle deferred fields.
         skip = set()
@@ -1345,10 +1339,7 @@ def get_cached_row(row, index_start, using,  klass_info, offset=0):
     if fields == (None,) * field_count:
         obj = None
     else:
-        if field_names:
-            obj = klass(**dict(zip(field_names, fields)))
-        else:
-            obj = klass(*fields)
+        obj = klass(*fields)
 
     # If an object was retrieved, set the database state.
     if obj:
@@ -1461,12 +1452,13 @@ class RawQuerySet(object):
             model_cls = deferred_class_factory(self.model, skip)
         else:
             model_cls = self.model
-            # All model's fields are present in the query. So, it is possible
-            # to use *args based model instantation. For each field of the model,
-            # record the query column position matching that field.
-            model_init_field_pos = []
-            for field in self.model._meta.fields:
-                model_init_field_pos.append(model_init_field_names[field.attname])
+        # For each field of the model, record the query column position matching
+        # that field. Note that we must use the get_init_attnames() method of
+        # the above fetched model_cls, because if it is a deferred model class
+        # its __init__ will expect the field in get_init_attnames order.
+        model_init_field_pos = []
+        for attname in model_cls._meta.get_init_attnames():
+            model_init_field_pos.append(model_init_field_names[attname])
         if need_resolv_columns:
             fields = [self.model_fields.get(c, None) for c in self.columns]
         # Begin looping through the query values.
@@ -1474,14 +1466,8 @@ class RawQuerySet(object):
             if need_resolv_columns:
                 values = compiler.resolve_columns(values, fields)
             # Associate fields to values
-            if skip:
-                model_init_kwargs = {}
-                for attname, pos in model_init_field_names.iteritems():
-                    model_init_kwargs[attname] = values[pos]
-                instance = model_cls(**model_init_kwargs)
-            else:
-                model_init_args = [values[pos] for pos in model_init_field_pos]
-                instance = model_cls(*model_init_args)
+            model_init_args = [values[pos] for pos in model_init_field_pos]
+            instance = model_cls(*model_init_args)
             if annotation_fields:
                 for column, pos in annotation_fields:
                     setattr(instance, column, values[pos])
diff --git a/django/db/models/query_utils.py b/django/db/models/query_utils.py
index a56ab5c..a3299eb 100644
--- a/django/db/models/query_utils.py
+++ b/django/db/models/query_utils.py
@@ -9,6 +9,7 @@ circular import difficulties.
 import weakref
 
 from django.db.backends import util
+from django.db.models.loading import get_model
 from django.utils import tree
 
 
@@ -146,23 +147,29 @@ def deferred_class_factory(model, attrs):
     being replaced with DeferredAttribute objects. The "pk_value" ties the
     deferred attributes to a particular instance of the model.
     """
-    class Meta:
-        proxy = True
-        app_label = model._meta.app_label
-
     # The app_cache wants a unique name for each model, otherwise the new class
     # won't be created (we get an old one back). Therefore, we generate the
     # name using the passed in attrs. It's OK to reuse an existing class
     # object if the attrs are identical.
     name = "%s_Deferred_%s" % (model.__name__, '_'.join(sorted(list(attrs))))
     name = util.truncate_name(name, 80, 32)
+    deferred_model = get_model(model._meta.app_label, name)
+    if deferred_model:
+        return deferred_model
+
+    class Meta:
+        proxy = True
+        app_label = model._meta.app_label
+
 
     overrides = dict([(attr, DeferredAttribute(attr, model))
             for attr in attrs])
     overrides["Meta"] = Meta
     overrides["__module__"] = model.__module__
     overrides["_deferred"] = True
-    return type(name, (model,), overrides)
+    deferred_model = type(name, (model,), overrides)
+    deferred_model._meta.set_loaded_fields(attrs)
+    return deferred_model
 
 # The above function is also used to unpickle model instances with deferred
 # fields.
