Skip to content

Commit 82aa86d

Browse files
committed
Fixed #35166 -- Reinstated support for python-memcached.
As of ``python-memcached>=1.62``, all previous incompatibilities have been resolved.
1 parent 70f39e4 commit 82aa86d

File tree

6 files changed

+72
-4
lines changed

6 files changed

+72
-4
lines changed

django/core/cache/backends/memcached.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"Memcached cache backend"
22

3+
import pickle
34
import re
45
import time
56

@@ -141,6 +142,17 @@ def validate_key(self, key):
141142
raise InvalidCacheKey(warning)
142143

143144

145+
class MemcachedCache(BaseMemcachedCache):
146+
"""An implementation of a cache binding using python-memcached."""
147+
148+
def __init__(self, server, params):
149+
import memcache
150+
super().__init__(
151+
server, params, library=memcache, value_not_found_exception=ValueError
152+
)
153+
self._options = {"pickleProtocol": pickle.HIGHEST_PROTOCOL} | self._options
154+
155+
144156
class PyLibMCCache(BaseMemcachedCache):
145157
"An implementation of a cache binding using pylibmc"
146158

docs/ref/settings.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ The cache backend to use. The built-in cache backends are:
153153
* ``'django.core.cache.backends.locmem.LocMemCache'``
154154
* ``'django.core.cache.backends.memcached.PyMemcacheCache'``
155155
* ``'django.core.cache.backends.memcached.PyLibMCCache'``
156+
* ``'django.core.cache.backends.memcached.MemcachedCache'``
156157
* ``'django.core.cache.backends.redis.RedisCache'``
157158

158159
You can use a cache backend that doesn't ship with Django by setting

docs/releases/5.1.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,9 @@ Asynchronous views
138138
Cache
139139
~~~~~
140140

141-
* ...
141+
* The ``django.core.cache.backends.memcached.MemcachedCache`` backend that was
142+
removed in Django 4.1 due to incompatibilities has been restored and requires
143+
``python-memcached>=1.62``.
142144

143145
CSRF
144146
~~~~

docs/topics/cache.txt

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,15 @@ database or filesystem usage.
7878

7979
After installing Memcached itself, you'll need to install a Memcached
8080
binding. There are several Python Memcached bindings available; the
81-
two supported by Django are :pypi:`pylibmc` and :pypi:`pymemcache`.
81+
three supported by Django are :pypi:`pymemcache`, :pypi:`pylibmc`, and
82+
:pypi:`python-memcached`.
8283

8384
To use Memcached with Django:
8485

8586
* Set :setting:`BACKEND <CACHES-BACKEND>` to
86-
``django.core.cache.backends.memcached.PyMemcacheCache`` or
87-
``django.core.cache.backends.memcached.PyLibMCCache`` (depending on your
87+
``django.core.cache.backends.memcached.PyMemcacheCache``,
88+
``django.core.cache.backends.memcached.PyLibMCCache``, or
89+
``django.core.cache.backends.memcached.MemcachedCache`` (depending on your
8890
chosen memcached binding)
8991

9092
* Set :setting:`LOCATION <CACHES-LOCATION>` to ``ip:port`` values,
@@ -166,6 +168,12 @@ permanent storage -- they're all intended to be solutions for caching, not
166168
storage -- but we point this out here because memory-based caching is
167169
particularly temporary.
168170

171+
.. versionchanged:: 5.1
172+
173+
The ``MemcachedCache`` backend is reinstated having previously been removed
174+
in Django 4.1 due to incompatibilities that have been resolved as of
175+
``python-memcached>=1.62``.
176+
169177
.. _redis:
170178

171179
Redis
@@ -525,6 +533,19 @@ of 60 seconds, and a maximum capacity of 1000 items::
525533
}
526534
}
527535

536+
Here's an example configuration for a ``python-memcached`` based backend with
537+
an object size limit of 2MB::
538+
539+
CACHES = {
540+
"default": {
541+
"BACKEND": "django.core.cache.backends.memcached.MemcachedCache",
542+
"LOCATION": "127.0.0.1:11211",
543+
"OPTIONS": {
544+
"server_max_value_length": 2 * 1024 ** 2,
545+
},
546+
}
547+
}
548+
528549
Here's an example configuration for a ``pylibmc`` based backend that enables
529550
the binary protocol, SASL authentication, and the ``ketama`` behavior mode::
530551

tests/cache/tests.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1446,6 +1446,9 @@ def test_lru_incr(self):
14461446
for _cache_params in settings.CACHES.values():
14471447
configured_caches[_cache_params["BACKEND"]] = _cache_params
14481448

1449+
MemcachedCache_params = configured_caches.get(
1450+
"django.core.cache.backends.memcached.MemcachedCache"
1451+
)
14491452
PyLibMCCache_params = configured_caches.get(
14501453
"django.core.cache.backends.memcached.PyLibMCCache"
14511454
)
@@ -1579,6 +1582,34 @@ def fail_set_multi(mapping, *args, **kwargs):
15791582
self.assertEqual(failing_keys, ["key"])
15801583

15811584

1585+
@unittest.skipUnless(MemcachedCache_params, "MemcachedCache backend not configured")
1586+
@override_settings(
1587+
CACHES=caches_setting_for_tests(
1588+
base=MemcachedCache_params,
1589+
exclude=memcached_excluded_caches,
1590+
)
1591+
)
1592+
class MemcachedCacheTests(BaseMemcachedTests, TestCase):
1593+
base_params = MemcachedCache_params
1594+
incr_decr_type_error = ValueError
1595+
1596+
def test_memcached_uses_highest_pickle_version(self):
1597+
for cache_key in settings.CACHES:
1598+
with self.subTest(cache_key=cache_key):
1599+
cache = caches[cache_key]
1600+
self.assertEqual(cache._cache.pickleProtocol, pickle.HIGHEST_PROTOCOL)
1601+
1602+
@override_settings(
1603+
CACHES=caches_setting_for_tests(
1604+
base=MemcachedCache_params,
1605+
exclude=memcached_excluded_caches,
1606+
OPTIONS={"server_max_value_length": 9999},
1607+
)
1608+
)
1609+
def test_memcached_options(self):
1610+
self.assertEqual(cache._cache.server_max_value_length, 9999)
1611+
1612+
15821613
@unittest.skipUnless(PyLibMCCache_params, "PyLibMCCache backend not configured")
15831614
@override_settings(
15841615
CACHES=caches_setting_for_tests(

tests/requirements/py3.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Pillow >= 6.2.1; sys.platform != 'win32' or python_version < '3.13'
1111
# pylibmc/libmemcached can't be built on Windows.
1212
pylibmc; sys.platform != 'win32'
1313
pymemcache >= 3.4.0
14+
python-memcached >= 1.62
1415
pywatchman; sys.platform != 'win32'
1516
PyYAML
1617
redis >= 3.4.0

0 commit comments

Comments
 (0)