Index: db/models/query.py
===================================================================
--- db/models/query.py	(revision 8070)
+++ db/models/query.py	(working copy)
@@ -625,9 +625,7 @@
         # names of the model fields to select.
 
     def iterator(self):
-        if (not self.extra_names and
-            len(self.field_names) != len(self.model._meta.fields)):
-            self.query.trim_extra_select(self.extra_names)
+        self.query.trim_extra_select(self.extra_names)
         names = self.query.extra_select.keys() + self.field_names
         for row in self.query.results_iter():
             yield dict(zip(names, row))
Index: db/models/sql/query.py
===================================================================
--- db/models/sql/query.py	(revision 8070)
+++ db/models/sql/query.py	(working copy)
@@ -78,8 +78,8 @@
 
         # These are for extensions. The contents are more or less appended
         # verbatim to the appropriate clause.
-        self.extra_select = {}  # Maps col_alias -> col_sql.
-        self.extra_select_params = ()
+        self.extra_select = SortedDict()  # Maps col_alias -> col_sql.
+        self.extra_select_params = SortedDict()
         self.extra_tables = ()
         self.extra_where = ()
         self.extra_params = ()
@@ -182,7 +182,7 @@
         obj.related_select_cols = []
         obj.max_depth = self.max_depth
         obj.extra_select = self.extra_select.copy()
-        obj.extra_select_params = self.extra_select_params
+        obj.extra_select_params = self.extra_select_params.copy()
         obj.extra_tables = self.extra_tables
         obj.extra_where = self.extra_where
         obj.extra_params = self.extra_params
@@ -255,9 +255,11 @@
         # get_from_clause() for details.
         from_, f_params = self.get_from_clause()
 
-        where, w_params = self.where.as_sql(qn=self.quote_name_unless_alias)
-        params = list(self.extra_select_params)
-
+        where, w_params = self.where.as_sql(qn=self.quote_name_unless_alias)
+        params = []
+        for extra_select_param in self.extra_select_params.values():
+            params.extend(extra_select_param)
+
         result = ['SELECT']
         if self.distinct:
             result.append('DISTINCT')
@@ -1503,8 +1505,8 @@
             self.distinct = False
         self.select = [select]
         self.select_fields = [None]
-        self.extra_select = {}
-        self.extra_select_params = ()
+        self.extra_select = SortedDict()
+        self.extra_select_params = SortedDict()
 
     def add_select_related(self, fields):
         """
@@ -1526,15 +1528,17 @@
         Adds data to the various extra_* attributes for user-created additions
         to the query.
         """
-        if select:
-            # The extra select might be ordered (because it will be accepting
-            # parameters).
-            if (isinstance(select, SortedDict) and
-                    not isinstance(self.extra_select, SortedDict)):
-                self.extra_select = SortedDict(self.extra_select)
-            self.extra_select.update(select)
-        if select_params:
-            self.extra_select_params += tuple(select_params)
+        if select:
+            select = SortedDict(select)
+            self.extra_select.append(select)
+            if select_params:
+                start = 0
+                for key in select.keys():
+                    number_of_params = select[key].count(" %s") # a %s in a sql statement is always preceded by a space, but could be at the very end of the string and then not be followed by a space
+                    self.extra_select_params.append({key:select_params[start:start+number_of_params]})
+                    start += number_of_params
+                if start != len(select_params):
+                    raise ValueError("The number of parameters expected by select= (%d) is not equal to the number of parameters given in select_params= (%d)" % (start, len(select_params)))
         if where:
             self.extra_where += tuple(where)
         if params:
@@ -1547,13 +1551,18 @@
     def trim_extra_select(self, names):
         """
         Removes any aliases in the extra_select dictionary that aren't in
-        'names'.
+        'names'.
+        Additionally remove the parameters that belonged to the removed aliases,
+        this ensures that the parameters stay aligned with the '%s'-replacements in the query
 
         This is needed if we are selecting certain values that don't incldue
         all of the extra_select names.
-        """
-        for key in set(self.extra_select).difference(set(names)):
-            del self.extra_select[key]
+        """
+        for key in reversed(self.extra_select.keys()):
+            if key not in names:                
+                del self.extra_select[key]
+                if self.extra_select_params.has_key(key): # sometimes a select statement has no params
+                    del self.extra_select_params[key]
 
     def set_start(self, start):
         """
@@ -1674,4 +1683,4 @@
     sender._meta._join_cache = {}
 
 dispatcher.connect(setup_join_cache, signal=signals.class_prepared)
-
+
Index: utils/datastructures.py
===================================================================
--- utils/datastructures.py	(revision 8070)
+++ utils/datastructures.py	(working copy)
@@ -121,6 +121,11 @@
     def update(self, dict_):
         for k, v in dict_.items():
             self.__setitem__(k, v)
+    
+    def append(self, data):
+        for key, value in data.iteritems():
+            super(SortedDict, self).__setitem__(key, value)
+            self.keyOrder.append(key)
 
     def setdefault(self, key, default):
         if key not in self.keyOrder:
@@ -406,3 +411,4 @@
             return self.func(value)
         return value
 
+
