Index: django/core/cache/backends/base.py
===================================================================
--- django/core/cache/backends/base.py	(revision 11268)
+++ django/core/cache/backends/base.py	(working copy)
@@ -83,6 +83,12 @@
         """
         return self.incr(key, -delta)
 
+    def flush(self):
+        """
+        Empties the cache
+        """
+        raise NotImplementedError
+
     def __contains__(self, key):
         """
         Returns True if the key is in the cache and has not expired.
Index: django/core/cache/backends/dummy.py
===================================================================
--- django/core/cache/backends/dummy.py	(revision 11268)
+++ django/core/cache/backends/dummy.py	(working copy)
@@ -23,3 +23,6 @@
 
     def has_key(self, *args, **kwargs):
         return False
+
+    def flush(self):
+        pass
Index: django/core/cache/backends/locmem.py
===================================================================
--- django/core/cache/backends/locmem.py	(revision 11268)
+++ django/core/cache/backends/locmem.py	(working copy)
@@ -108,10 +108,13 @@
         finally:
             self._lock.writer_leaves()
 
+    def flush(self):
+        self._cache.clear()
+        self._expire_info.clear()
+
     def _cull(self):
         if self._cull_frequency == 0:
-            self._cache.clear()
-            self._expire_info.clear()
+            self.flush()
         else:
             doomed = [k for (i, k) in enumerate(self._cache) if i % self._cull_frequency == 0]
             for k in doomed:
Index: django/core/cache/backends/filebased.py
===================================================================
--- django/core/cache/backends/filebased.py	(revision 11268)
+++ django/core/cache/backends/filebased.py	(working copy)
@@ -103,6 +103,20 @@
         except (IOError, OSError, EOFError, pickle.PickleError):
             return False
 
+    def flush(self):
+        try:
+            filelist = os.listdir(self._dir)
+        except (IOError, OSError):
+            return
+        for topdir in filelist:
+            topdir = os.path.join(self._dir, topdir)
+            try:
+                for root, _, files in os.walk(topdir):
+                    for f in files:
+                        self._delete(os.path.join(root, f))
+            except (IOError, OSError):
+                pass
+
     def _cull(self):
         if int(self._num_entries) < self._max_entries:
             return
@@ -113,7 +127,7 @@
             return
 
         if self._cull_frequency == 0:
-            doomed = filelist
+            doomed = [os.path.join(self._dir, k) for k in filelist]
         else:
             doomed = [os.path.join(self._dir, k) for (i, k) in enumerate(filelist) if i % self._cull_frequency == 0]
 
Index: django/core/cache/backends/db.py
===================================================================
--- django/core/cache/backends/db.py	(revision 11268)
+++ django/core/cache/backends/db.py	(working copy)
@@ -52,7 +52,7 @@
         num = cursor.fetchone()[0]
         now = datetime.now().replace(microsecond=0)
         exp = datetime.fromtimestamp(time.time() + timeout).replace(microsecond=0)
-        if num > self._max_entries:
+        if num >= self._max_entries:
             self._cull(cursor, now)
         encoded = base64.encodestring(pickle.dumps(value, 2)).strip()
         cursor.execute("SELECT cache_key, expires FROM %s WHERE cache_key = %%s" % self._table, [key])
@@ -82,13 +82,20 @@
         cursor.execute("SELECT cache_key FROM %s WHERE cache_key = %%s and expires > %%s" % self._table, [key, now])
         return cursor.fetchone() is not None
 
+    def flush(self):
+        cursor = connection.cursor()
+        self._flush(cursor)
+
+    def _flush(self, cursor):
+        cursor.execute("DELETE FROM %s" % self._table)
+
     def _cull(self, cursor, now):
         if self._cull_frequency == 0:
-            cursor.execute("DELETE FROM %s" % self._table)
+            self._flush(cursor)
         else:
             cursor.execute("DELETE FROM %s WHERE expires < %%s" % self._table, [str(now)])
             cursor.execute("SELECT COUNT(*) FROM %s" % self._table)
             num = cursor.fetchone()[0]
-            if num > self._max_entries:
+            if num >= self._max_entries:
                 cursor.execute("SELECT cache_key FROM %s ORDER BY cache_key LIMIT 1 OFFSET %%s" % self._table, [num / self._cull_frequency])
                 cursor.execute("DELETE FROM %s WHERE cache_key < %%s" % self._table, [cursor.fetchone()[0]])
Index: django/core/cache/backends/memcached.py
===================================================================
--- django/core/cache/backends/memcached.py	(revision 11268)
+++ django/core/cache/backends/memcached.py	(working copy)
@@ -44,7 +44,10 @@
 
     def close(self, **kwargs):
         self._cache.disconnect_all()
-
+    
+    def flush(self):
+        self._cache.flush_all()      
+    
     def incr(self, key, delta=1):
         return self._cache.incr(key, delta)
 
Index: tests/regressiontests/cache/tests.py
===================================================================
--- tests/regressiontests/cache/tests.py	(revision 11268)
+++ tests/regressiontests/cache/tests.py	(working copy)
@@ -89,6 +89,10 @@
         self.assertRaises(ValueError, self.cache.decr, 'answer')
         self.assertRaises(ValueError, self.cache.decr, 'does_not_exist')
 
+    def test_flush(self):
+        "Flushing dummy cache does nothing but should not throw an exception"
+        self.cache.flush()
+
     def test_data_types(self):
         "All data types are ignored equally by the dummy cache"
         stuff = {
@@ -197,6 +201,46 @@
         self.assertEqual(self.cache.get('answer'), 32)
         self.assertRaises(ValueError, self.cache.decr, 'does_not_exist')
 
+    def test_flush(self):
+        # Flushing removes everything from the cache
+        self.cache.set("cheese1", "Venezuelan Beaver")
+        self.cache.set("cheese2", "Czech Sheep's Milk")
+        self.cache.flush()
+        self.assertEqual(self.cache.get('cheese1'), None)
+        self.assertEqual(self.cache.get('cheese2'), None)
+    
+    def test_culling(self):
+        # After max_entries, remove 1/cull_frequency entries
+        cache = self._get_culling_cache(4,2)
+        cache.set("cheese1", "Venezuelan Beaver")
+        cache.set("cheese2", "Czech Sheep's Milk")
+        cache.set("cheese3", "Ilchester")
+        cache.set("cheese4", "Cheddar")
+        cache.set("cheese5", "Limburger")
+
+        count = 0
+        if cache.get('cheese1'): count += 1
+        if cache.get('cheese2'): count += 1
+        if cache.get('cheese3'): count += 1
+        if cache.get('cheese4'): count += 1
+        if cache.get('cheese5'): count += 1
+
+        self.assertEqual(3, count)
+
+    def test_cull_zero(self):
+        # Cull_frequency of 0 remove all entries
+        cache = self._get_culling_cache(2,0)
+        cache.set("cheese1", "Venezuelan Beaver")
+        cache.set("cheese2", "Czech Sheep's Milk")
+        cache.set("cheese3", "Ilchester")
+        self.assertEqual(cache.get('cheese1'), None)
+        self.assertEqual(cache.get('cheese2'), None)
+        self.assertEqual(cache.get('cheese3'), 'Ilchester')
+
+    def _get_culling_cache(self, max_entries, cull_frequency):
+        "Returns a cache with given max_entries and cull_frequency"
+        raise NotImplementedError
+
     def test_data_types(self):
         # Many different data types can be cached
         stuff = {
@@ -246,10 +290,18 @@
         cursor = connection.cursor()
         cursor.execute('DROP TABLE test_cache_table');
 
+    def _get_culling_cache(self, max_entries, cull_frequency):
+        return get_cache('db://test_cache_table?max_entries=%s&cull_frequency=%s' %
+                         (max_entries, cull_frequency))
+
 class LocMemCacheTests(unittest.TestCase, BaseCacheTests):
     def setUp(self):
         self.cache = get_cache('locmem://')
 
+    def _get_culling_cache(self, max_entries, cull_frequency):
+        return get_cache('locmem://?max_entries=%s&cull_frequency=%s' %
+                         (max_entries, cull_frequency))
+
 # memcached backend isn't guaranteed to be available.
 # To check the memcached backend, the test settings file will
 # need to contain a CACHE_BACKEND setting that points at
@@ -259,6 +311,14 @@
         def setUp(self):
             self.cache = get_cache(settings.CACHE_BACKEND)
 
+        def test_culling(self):
+            # No culling tests -- memcached does its own thing
+            pass
+
+        def test_cull_zero(self):
+            # No culling tests -- memcached does its own thing
+            pass
+
 class FileBasedCacheTests(unittest.TestCase, BaseCacheTests):
     """
     Specific test cases for the file-based cache.
@@ -270,6 +330,10 @@
     def tearDown(self):
         shutil.rmtree(self.dirname)
 
+    def _get_culling_cache(self, max_entries, cull_frequency):
+        return get_cache('file://%s?max_entries=%s&cull_frequency=%s' %
+                         (self.dirname, max_entries, cull_frequency))
+    
     def test_hashing(self):
         """Test that keys are hashed into subdirectories correctly"""
         self.cache.set("foo", "bar")
