Index: django/http/__init__.py
===================================================================
--- django/http/__init__.py	(revision 2562)
+++ django/http/__init__.py	(working copy)
@@ -69,22 +69,35 @@
 class QueryDict(MultiValueDict):
     """A specialized MultiValueDict that takes a query string when initialized.
     This is immutable unless you create a copy of it."""
-    def __init__(self, query_string):
+    def __init__(self, query_string, mutable=False):
         MultiValueDict.__init__(self)
         self._mutable = True
         for key, value in parse_qsl((query_string or ''), True): # keep_blank_values=True
             self.appendlist(key, value)
-        self._mutable = False
+        self._mutable = mutable
 
     def _assert_mutable(self):
         if not self._mutable:
             raise AttributeError, "This QueryDict instance is immutable"
 
-    def _setitem_if_mutable(self, key, value):
+    def __setitem__(self, key, value):
         self._assert_mutable()
         MultiValueDict.__setitem__(self, key, value)
-    __setitem__ = _setitem_if_mutable
 
+    def __copy__(self):
+        result = self.__class__('', mutable=True)
+        for key, value in dict.items(self):
+            dict.__setitem__(result, key, value)
+        return result
+
+    def __deepcopy__(self, memo={}):
+        import copy
+        result = self.__class__('', mutable=True)
+        memo[id(self)] = result
+        for key, value in dict.items(self):
+            dict.__setitem__(result, copy.deepcopy(key, memo), copy.deepcopy(value, memo))
+        return result
+
     def setlist(self, key, list_):
         self._assert_mutable()
         MultiValueDict.setlist(self, key, list_)
@@ -115,13 +128,7 @@
 
     def copy(self):
         "Returns a mutable copy of this object."
-        import copy
-        # Our custom __setitem__ must be disabled for copying machinery.
-        QueryDict.__setitem__ = dict.__setitem__
-        cp = copy.deepcopy(self)
-        QueryDict.__setitem__ = QueryDict._setitem_if_mutable
-        cp._mutable = True
-        return cp
+        return self.__deepcopy__()
 
     def urlencode(self):
         output = []
Index: django/utils/datastructures.py
===================================================================
--- django/utils/datastructures.py	(revision 2562)
+++ django/utils/datastructures.py	(working copy)
@@ -117,10 +117,20 @@
         except IndexError:
             return []
 
-    def _setitem_list(self, key, value):
+    def __setitem__(self, key, value):
         dict.__setitem__(self, key, [value])
-    __setitem__ = _setitem_list
 
+    def __copy__(self):
+        return self.__class__(dict.items(self))
+
+    def __deepcopy__(self, memo={}):
+        import copy
+        result = self.__class__()
+        memo[id(self)] = result
+        for key, value in dict.items(self):
+            dict.__setitem__(result, copy.deepcopy(key, memo), copy.deepcopy(value, memo))
+        return result
+
     def get(self, key, default=None):
         "Returns the default value if the requested data doesn't exist"
         try:
@@ -173,12 +183,7 @@
 
     def copy(self):
         "Returns a copy of this object."
-        import copy
-        # Our custom __setitem__ must be disabled for copying machinery.
-        MultiValueDict.__setitem__ = dict.__setitem__
-        cp = copy.deepcopy(self)
-        MultiValueDict.__setitem__ = MultiValueDict._setitem_list
-        return cp
+        return self.__deepcopy__()
 
     def update(self, other_dict):
         "update() extends rather than replaces existing key lists."
