Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 5 additions & 15 deletions django/db/__init__.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,9 @@
from django.core import signals
from django.db.utils import (
DEFAULT_DB_ALIAS,
DJANGO_VERSION_PICKLE_KEY,
ConnectionHandler,
ConnectionRouter,
DatabaseError,
DataError,
Error,
IntegrityError,
InterfaceError,
InternalError,
NotSupportedError,
OperationalError,
ProgrammingError,
)
from django.db.utils import (DEFAULT_DB_ALIAS, DJANGO_VERSION_PICKLE_KEY,
ConnectionHandler, ConnectionRouter,
DatabaseError, DataError, Error, IntegrityError,
InterfaceError, InternalError, NotSupportedError,
OperationalError, ProgrammingError)
from django.utils.connection import ConnectionProxy

__all__ = [
Expand Down
14 changes: 8 additions & 6 deletions django/dispatch/dispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ def __init__(self, use_caching=False):
# .disconnect() is called and populated on send().
self.sender_receivers_cache = weakref.WeakKeyDictionary() if use_caching else {}
self._dead_receivers = False
self._lookup_keys = set()

def connect(self, receiver, sender=None, weak=True, dispatch_uid=None):
"""
Expand Down Expand Up @@ -119,10 +120,7 @@ def connect(self, receiver, sender=None, weak=True, dispatch_uid=None):
receiver = ref(receiver)
weakref.finalize(receiver_object, self._flag_dead_receivers)

# Keep a weakref to sender if possible to ensure associated receivers
# are cleared if it gets garbage collected. This ensures there is no
# id(sender) collisions for distinct senders with non-overlapping
# lifetimes.
# Manage sender weakref as before
sender_ref = None
if sender is not None:
try:
Expand All @@ -132,9 +130,13 @@ def connect(self, receiver, sender=None, weak=True, dispatch_uid=None):

with self.lock:
self._clear_dead_receivers()
if not any(r_key == lookup_key for r_key, _, _, _ in self.receivers):
# Use set for fast lookup, reduces connect time from O(n) to O(1)
if lookup_key not in self._lookup_keys:
self.receivers.append((lookup_key, receiver, sender_ref, is_async))
self.sender_receivers_cache.clear()
self._lookup_keys.add(lookup_key)
# Only clear sender_receivers_cache if caching is used
if self.use_caching:
self.sender_receivers_cache.clear()

def disconnect(self, receiver=None, sender=None, dispatch_uid=None):
"""
Expand Down
7 changes: 6 additions & 1 deletion django/test/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
from django.utils.translation import deactivate
from django.utils.version import PYPY

_reset_queries_connected = False

try:
import jinja2
except ImportError:
Expand Down Expand Up @@ -737,8 +739,11 @@ def __enter__(self):

def __exit__(self, exc_type, exc_value, traceback):
self.connection.force_debug_cursor = self.force_debug_cursor
if self.reset_queries_disconnected:
global _reset_queries_connected
# Only (re)connect if we previously disconnected and not already connected
if self.reset_queries_disconnected and not _reset_queries_connected:
request_started.connect(reset_queries)
_reset_queries_connected = True
if exc_type is not None:
return
self.final_queries = len(self.connection.queries_log)
Expand Down