Skip to content

Commit f9e39bb

Browse files
committed
edits
1 parent 64842be commit f9e39bb

File tree

4 files changed

+37
-48
lines changed

4 files changed

+37
-48
lines changed

django_mongodb_backend/cache.py

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ def __init__(self, protocol=None):
1414
self.protocol = pickle.HIGHEST_PROTOCOL if protocol is None else protocol
1515

1616
def dumps(self, obj):
17-
# Only skip pickling for integers, a int subclasses as bool should be
18-
# pickled.
17+
# For better incr() and decr() atomicity, don't pickle integers.
18+
# Using type() rather than isinstance() matches only integers and not
19+
# subclasses like bool.
1920
if type(obj) is int: # noqa: E721
2021
return obj
2122
return pickle.dumps(obj, self.protocol)
@@ -59,10 +60,7 @@ def collection_for_write(self):
5960
return connections[db].get_collection(self._collection_name)
6061

6162
def get(self, key, default=None, version=None):
62-
result = self.get_many([key], version)
63-
if result:
64-
return result[key]
65-
return default
63+
return self.get_many([key], version).get(key, default)
6664

6765
def _filter_expired(self, expired=False):
6866
not_expired_filter = [{"expires_at": {"$gte": datetime.utcnow()}}, {"expires_at": None}]
@@ -80,7 +78,6 @@ def get_many(self, keys, version=None):
8078

8179
def set(self, key, value, timeout=DEFAULT_TIMEOUT, version=None):
8280
key = self.make_and_validate_key(key, version=version)
83-
serialized_data = self.serializer.dumps(value)
8481
num = self.collection_for_write.count_documents({}, hint="_id_")
8582
if num >= self._max_entries:
8683
self._cull(num)
@@ -89,16 +86,15 @@ def set(self, key, value, timeout=DEFAULT_TIMEOUT, version=None):
8986
{
9087
"$set": {
9188
"key": key,
92-
"value": serialized_data,
89+
"value": self.serializer.dumps(value),
9390
"expires_at": self._get_expiration_time(timeout),
9491
}
9592
},
96-
True,
93+
upsert=True,
9794
)
9895

9996
def add(self, key, value, timeout=DEFAULT_TIMEOUT, version=None):
10097
key = self.make_and_validate_key(key, version=version)
101-
serialized_data = self.serializer.dumps(value)
10298
num = self.collection_for_write.count_documents({}, hint="_id_")
10399
if num >= self._max_entries:
104100
self._cull(num)
@@ -108,11 +104,11 @@ def add(self, key, value, timeout=DEFAULT_TIMEOUT, version=None):
108104
{
109105
"$set": {
110106
"key": key,
111-
"value": serialized_data,
107+
"value": self.serializer.dumps(value),
112108
"expires_at": self._get_expiration_time(timeout),
113109
}
114110
},
115-
True,
111+
upsert=True,
116112
)
117113
except DuplicateKeyError:
118114
return False
@@ -171,7 +167,8 @@ def incr(self, key, delta=1, version=None):
171167
return_document=ReturnDocument.AFTER,
172168
)
173169
except OperationFailure as ex:
174-
raise TypeError("Cannot apply incr to a value of non-numeric type") from ex
170+
method_name = "incr" if delta >= 1 else "decr"
171+
raise TypeError(f"Cannot apply {method_name}() to a value of non-numeric type.") from ex
175172
# Not exists
176173
if updated is None:
177174
raise ValueError(f"Key '{key}' not found.") from None

django_mongodb_backend/creation.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
from django.conf import settings
2-
from django.core.cache import caches
32
from django.db.backends.base.creation import BaseDatabaseCreation
43

5-
from django_mongodb_backend.cache import MongoDBCache
4+
from django_mongodb_backend.management.commands.createcachecollection import (
5+
Command as CreateCacheCollection,
6+
)
67

78

89
class DatabaseCreation(BaseDatabaseCreation):
@@ -22,12 +23,9 @@ def _destroy_test_db(self, test_database_name, verbosity):
2223

2324
def create_test_db(self, *args, **kwargs):
2425
test_database_name = super().create_test_db(*args, **kwargs)
25-
# Create cache collections
26-
for cache_alias in settings.CACHES:
27-
cache = caches[cache_alias]
28-
if isinstance(cache, MongoDBCache):
29-
connection = cache._db_to_write
30-
if cache._collection_name in connection.introspection.table_names():
31-
continue
32-
cache.create_indexes()
26+
# Not using call_command() avoids the requirement to put
27+
# "django_mongodb_backend" in INSTALLED_APPS.
28+
CreateCacheCollection().handle(
29+
database=self.connection.alias, verbosity=kwargs["verbosity"]
30+
)
3331
return test_database_name

docs/source/releases/5.1.x.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22
Django MongoDB Backend 5.1.x
33
============================
44

5+
5.1.0 beta 2
6+
============
7+
8+
*Unreleased*
9+
10+
- Added support for :doc:`database caching </topics/cache>`.
11+
512
5.1.0 beta 1
613
============
714

tests/cache_/tests.py

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
"""These tests are forked from Django's tests/cache/tests.py."""
12
import os
23
import pickle
34
import time
@@ -9,13 +10,8 @@
910
from django.core import management
1011
from django.core.cache import DEFAULT_CACHE_ALIAS, CacheKeyWarning, cache, caches
1112
from django.core.cache.backends.base import InvalidCacheBackendError
12-
from django.http import (
13-
HttpResponse,
14-
)
15-
from django.middleware.cache import (
16-
FetchFromCacheMiddleware,
17-
UpdateCacheMiddleware,
18-
)
13+
from django.http import HttpResponse
14+
from django.middleware.cache import FetchFromCacheMiddleware, UpdateCacheMiddleware
1915
from django.test import RequestFactory, TestCase, modify_settings, override_settings
2016

2117
from .models import Poll, expensive_calculation
@@ -97,12 +93,8 @@ def caches_setting_for_tests(base=None, exclude=None, **params):
9793

9894

9995
class BaseCacheTests:
100-
# A common set of tests to apply to all cache backends
10196
factory = RequestFactory()
102-
103-
# Some clients raise custom exceptions when .incr() or .decr() are called
104-
# with a non-integer value.
105-
incr_decr_type_error = TypeError
97+
incr_decr_type_error_msg = "Cannot apply %s() to a value of non-numeric type."
10698

10799
def tearDown(self):
108100
cache.clear()
@@ -186,12 +178,12 @@ def test_incr(self):
186178
self.assertEqual(cache.incr("answer", 10), 52)
187179
self.assertEqual(cache.get("answer"), 52)
188180
self.assertEqual(cache.incr("answer", -10), 42)
189-
with self.assertRaises(ValueError):
181+
with self.assertRaisesMessage(ValueError, "Key 'does_not_exist' not found."):
190182
cache.incr("does_not_exist")
191-
with self.assertRaises(ValueError):
183+
with self.assertRaisesMessage(ValueError, "Key 'does_not_exist' not found."):
192184
cache.incr("does_not_exist", -1)
193185
cache.set("null", None)
194-
with self.assertRaises(self.incr_decr_type_error):
186+
with self.assertRaisesMessage(TypeError, self.incr_decr_type_error_msg % "incr"):
195187
cache.incr("null")
196188

197189
def test_decr(self):
@@ -202,12 +194,12 @@ def test_decr(self):
202194
self.assertEqual(cache.decr("answer", 10), 32)
203195
self.assertEqual(cache.get("answer"), 32)
204196
self.assertEqual(cache.decr("answer", -10), 42)
205-
with self.assertRaises(ValueError):
197+
with self.assertRaisesMessage(ValueError, "Key 'does_not_exist' not found."):
206198
cache.decr("does_not_exist")
207-
with self.assertRaises(ValueError):
199+
with self.assertRaisesMessage(ValueError, "Key 'does_not_exist' not found."):
208200
cache.incr("does_not_exist", -1)
209201
cache.set("null", None)
210-
with self.assertRaises(self.incr_decr_type_error):
202+
with self.assertRaisesMessage(TypeError, self.incr_decr_type_error_msg % "decr"):
211203
cache.decr("null")
212204

213205
def test_close(self):
@@ -846,12 +838,7 @@ def test_custom_key_func(self):
846838
self.assertEqual(caches["custom_key"].get("answer2"), 42)
847839
self.assertEqual(caches["custom_key2"].get("answer2"), 42)
848840

849-
@override_settings(
850-
CACHE_MIDDLEWARE_ALIAS=DEFAULT_CACHE_ALIAS,
851-
)
852-
@modify_settings(
853-
INSTALLED_APPS={"prepend": "django_mongodb_backend"},
854-
)
841+
@override_settings(CACHE_MIDDLEWARE_ALIAS=DEFAULT_CACHE_ALIAS)
855842
def test_cache_write_unpicklable_object(self):
856843
fetch_middleware = FetchFromCacheMiddleware(empty_response)
857844

@@ -1003,7 +990,7 @@ def allow_migrate(self, db, app_label, **hints):
1003990
@modify_settings(
1004991
INSTALLED_APPS={"prepend": "django_mongodb_backend"},
1005992
)
1006-
class CreateCacheTableForDBCacheTests(TestCase):
993+
class CreateCacheCollectionTests(TestCase):
1007994
databases = {"default", "other"}
1008995

1009996
@override_settings(DATABASE_ROUTERS=[DBCacheRouter()])

0 commit comments

Comments
 (0)