Ticket #5415: db_signal_r6979.patch
File db_signal_r6979.patch, 7.7 KB (added by , 17 years ago) |
---|
-
django/db/__init__.py
1 1 import os 2 2 from django.conf import settings 3 from django.core import signals 3 from django.core import signals as core_signals 4 4 from django.core.exceptions import ImproperlyConfigured 5 5 from django.dispatch import dispatcher 6 6 from django.utils.functional import curry … … 54 54 55 55 # Register an event that closes the database connection 56 56 # when a Django request is finished. 57 dispatcher.connect(connection.close, signal= signals.request_finished)57 dispatcher.connect(connection.close, signal=core_signals.request_finished) 58 58 59 59 # Register an event that resets connection.queries 60 60 # when a Django request is started. 61 61 def reset_queries(): 62 62 connection.queries = [] 63 dispatcher.connect(reset_queries, signal= signals.request_started)63 dispatcher.connect(reset_queries, signal=core_signals.request_started) 64 64 65 65 # Register an event that rolls back the connection 66 66 # when a Django request has an exception. 67 67 def _rollback_on_exception(): 68 68 from django.db import transaction 69 69 transaction.rollback_unless_managed() 70 dispatcher.connect(_rollback_on_exception, signal= signals.got_request_exception)70 dispatcher.connect(_rollback_on_exception, signal=core_signals.got_request_exception) -
django/db/signals.py
1 query_execute = object() -
django/db/backends/util.py
1 1 import datetime 2 from django.db import signals 3 from django.dispatch import dispatcher 2 4 import md5 3 5 from time import time 4 6 … … 41 43 else: 42 44 return getattr(self.cursor, attr) 43 45 46 def __iter__(self): 47 return iter(self.cursor) 48 49 50 class CursorSignalWrapper(object): 51 def __init__(self, cursor, db): 52 self.cursor = cursor 53 self.db = db # Instance of a BaseDatabaseWrapper subclass 54 55 def execute(self, sql, params=()): 56 start = time() 57 try: 58 return self.cursor.execute(sql, params) 59 finally: 60 stop = time() 61 dispatcher.send(signal=signals.query_execute, sender=self, sql=sql, params=params, time=stop-start) 62 63 def executemany(self, sql, param_list): 64 start = time() 65 try: 66 return self.cursor.executemany(sql, param_list) 67 finally: 68 stop = time() 69 # XXX: Should this be a special signal that only gets called once for efficiency? 70 for params in param_list: 71 dispatcher.send(signal=signals.query_execute, sender=self, sql=sql, params=params, time=stop-start) 72 73 def __getattr__(self, attr): 74 if attr in self.__dict__: 75 return self.__dict__[attr] 76 else: 77 return getattr(self.cursor, attr) 78 79 def __iter__(self): 80 return iter(self.cursor) 81 82 44 83 ############################################### 45 84 # Converters from database (string) to Python # 46 85 ############################################### -
django/db/backends/__init__.py
14 14 self.connection = None 15 15 self.queries = [] 16 16 self.options = kwargs 17 self.use_signal_cursor = None 17 18 18 19 def _commit(self): 19 20 if self.connection is not None: … … 32 33 from django.conf import settings 33 34 cursor = self._cursor(settings) 34 35 if settings.DEBUG: 35 return self.make_debug_cursor(cursor) 36 return self.make_signal_cursor(self.make_debug_cursor(cursor)) 37 elif self.use_signal_cursor: 38 return self.make_signal_cursor(cursor) 36 39 return cursor 37 40 38 41 def make_debug_cursor(self, cursor): 39 42 from django.db.backends import util 40 43 return util.CursorDebugWrapper(cursor, self) 44 45 def make_signal_cursor(self, cursor): 46 from django.db.backends import util 47 return util.CursorSignalWrapper(cursor, self) 41 48 49 42 50 class BaseDatabaseFeatures(object): 43 51 allows_group_by_ordinal = True 44 52 allows_unique_and_pk = True -
tests/modeltests/select_related/models.py
7 7 the select-related behavior will traverse. 8 8 """ 9 9 10 from django.db import models 10 from django.db import models, signals 11 from django.dispatch import dispatcher 11 12 12 13 # Who remembers high school biology? 13 14 … … 75 76 obj.save() 76 77 parent = obj 77 78 79 class QueryCounter(object): 80 counter = 0 81 82 @staticmethod 83 def add(): 84 QueryCounter.counter += 1 85 86 @staticmethod 87 def clear(): 88 QueryCounter.counter = 0 89 90 91 def track_query(sender, *args, **kwargs): 92 QueryCounter.add() 93 dispatcher.connect(track_query, signal=signals.query_execute, weak=False) 94 78 95 __test__ = {'API_TESTS':""" 79 96 80 97 # Set up. … … 92 109 93 110 # Normally, accessing FKs doesn't fill in related objects: 94 111 >>> db.reset_queries() 112 >>> QueryCounter.clear() 95 113 >>> fly = Species.objects.get(name="melanogaster") 96 114 >>> fly.genus.family.order.klass.phylum.kingdom.domain 97 115 <Domain: Eukaryota> 98 116 >>> len(db.connection.queries) 99 117 8 118 >>> QueryCounter.counter 119 8 100 120 101 121 # However, a select_related() call will fill in those related objects without any extra queries: 102 122 >>> db.reset_queries() 123 >>> QueryCounter.clear() 103 124 >>> person = Species.objects.select_related().get(name="sapiens") 104 125 >>> person.genus.family.order.klass.phylum.kingdom.domain 105 126 <Domain: Eukaryota> 106 127 >>> len(db.connection.queries) 107 128 1 129 >>> QueryCounter.counter 130 1 108 131 109 132 # select_related() also of course applies to entire lists, not just items. 110 133 # Without select_related() 111 134 >>> db.reset_queries() 135 >>> QueryCounter.clear() 112 136 >>> world = Species.objects.all() 113 137 >>> [o.genus.family for o in world] 114 138 [<Family: Drosophilidae>, <Family: Hominidae>, <Family: Fabaceae>, <Family: Amanitacae>] 115 139 >>> len(db.connection.queries) 116 140 9 141 >>> QueryCounter.counter 142 9 117 143 118 144 # With select_related(): 119 145 >>> db.reset_queries() 146 >>> QueryCounter.clear() 120 147 >>> world = Species.objects.all().select_related() 121 148 >>> [o.genus.family for o in world] 122 149 [<Family: Drosophilidae>, <Family: Hominidae>, <Family: Fabaceae>, <Family: Amanitacae>] 123 150 >>> len(db.connection.queries) 124 151 1 152 >>> QueryCounter.counter 153 1 125 154 126 155 # The "depth" argument to select_related() will stop the descent at a particular level: 127 156 >>> db.reset_queries() 157 >>> QueryCounter.clear() 128 158 >>> pea = Species.objects.select_related(depth=1).get(name="sativum") 129 159 >>> pea.genus.family.order.klass.phylum.kingdom.domain 130 160 <Domain: Eukaryota> … … 132 162 # Notice: one few query than above because of depth=1 133 163 >>> len(db.connection.queries) 134 164 7 165 >>> QueryCounter.counter 166 7 135 167 136 168 >>> db.reset_queries() 169 >>> QueryCounter.clear() 137 170 >>> pea = Species.objects.select_related(depth=5).get(name="sativum") 138 171 >>> pea.genus.family.order.klass.phylum.kingdom.domain 139 172 <Domain: Eukaryota> 140 173 >>> len(db.connection.queries) 141 174 3 175 >>> QueryCounter.counter 176 3 142 177 143 178 >>> db.reset_queries() 179 >>> QueryCounter.clear() 144 180 >>> world = Species.objects.all().select_related(depth=2) 145 181 >>> [o.genus.family.order for o in world] 146 182 [<Order: Diptera>, <Order: Primates>, <Order: Fabales>, <Order: Agaricales>] 147 183 >>> len(db.connection.queries) 148 184 5 185 >>> QueryCounter.counter 186 5 149 187 150 188 # Reset DEBUG to where we found it. 151 189 >>> settings.DEBUG = False