Index: db/models/query.py
===================================================================
--- db/models/query.py	(revision 7199)
+++ db/models/query.py	(working copy)
@@ -1185,3 +1185,42 @@
             setattr(instance, cls._meta.pk.attname, None)
 
     transaction.commit_unless_managed()
+
+
+class SafeReprQuerySet(QuerySet):
+    """ This QuerySet class will be safe to `repr`.
+    That means:
+        1. If the QuerySet object passed is already evaluated, repr will behave as before.
+        2. If the QuerySet object has not been evaluated, repr will be the SQL.
+
+    Example usage::
+
+        >>> if isinstance(qs, QuerySet):
+        >>>     qs = SafeReprQuerySet.from_queryset(qs)
+        >>> print repr(qs)
+    """
+
+    @classmethod
+    def from_queryset(cls, queryset):
+        """ Take a queryset and create a SafeReprQuerySet from it. """
+        assert isinstance(queryset, QuerySet), "from_queryset requires a QuerySet object, recieved %r" % queryset
+        new_queryset = queryset._clone(klass=cls, _result_cache=queryset._result_cache)
+        new_queryset._old_class = queryset.__class__
+        return new_queryset
+
+
+    def __repr__(self):
+        """ Return a representation of this object that doesn't evaluate the SQL. """
+        old_class = self._old_class.__name__
+        if self._result_cache:
+            return QuerySet.__repr__(self)
+
+        try:
+            select, sql, params = self._get_sql_clause()
+            sql = ("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql)
+            try:
+                return '<%s SQL:%r>' % (old_class, sql % tuple(params))
+            except:
+                return '<%s SQL:%r>' % (old_class, [sql, params])
+        except:
+            return '<%s object>' % old_class
Index: views/debug.py
===================================================================
--- views/debug.py	(revision 7199)
+++ views/debug.py	(working copy)
@@ -463,7 +463,7 @@
                 {% for var in frame.vars|dictsort:"0" %}
                   <tr>
                     <td>{{ var.0|escape }}</td>
-                    <td class="code"><div>{{ var.1|pprint|escape }}</div></td>
+                    <td class="code"><div>{{ var.1|safe_pprint|escape }}</div></td>
                   </tr>
                 {% endfor %}
               </tbody>
Index: template/defaultfilters.py
===================================================================
--- template/defaultfilters.py	(revision 7199)
+++ template/defaultfilters.py	(working copy)
@@ -790,6 +790,17 @@
         return u"Error in formatting: %s" % force_unicode(e, errors="replace")
 pprint.is_safe = True
 
+def safe_pprint(value):
+    """A wrapper around pprint that ensures that QuerySets don't get evaluated.
+    If the QuerySet results have already been used, they will be cached and the
+    result will be identical to normal pprint. However, if the QuerySet has not
+    been used, this filter will return the SQL that the QuerySet would execute."""
+    from django.db.models.query import QuerySet, SafeReprQuerySet
+    if isinstance(value, QuerySet) and not isinstance(value, SafeReprQuerySet):
+        value = SafeReprQuerySet.from_queryset(value)
+    return pprint(value)
+    
+
 # Syntax: register.filter(name of filter, callback)
 register.filter(add)
 register.filter(addslashes)
@@ -828,6 +839,7 @@
 register.filter(random)
 register.filter(rjust)
 register.filter(safe)
+register.filter(safe_pprint)
 register.filter('slice', slice_)
 register.filter(slugify)
 register.filter(stringformat)
