Ticket #5415: db_signal_r6702.2.patch

File db_signal_r6702.2.patch, 8.7 KB (added by gav, 7 years ago)
  • django/db/__init__.py

     
    11import os
    22from django.conf import settings
    3 from django.core import signals
     3from django.core import signals as core_signals
    44from django.core.exceptions import ImproperlyConfigured
    55from django.dispatch import dispatcher
    66from django.utils.functional import curry
     
    5454
    5555# Register an event that closes the database connection
    5656# when a Django request is finished.
    57 dispatcher.connect(connection.close, signal=signals.request_finished)
     57dispatcher.connect(connection.close, signal=core_signals.request_finished)
    5858
    59 # Register an event that resets connection.queries
    60 # when a Django request is started.
    61 def reset_queries():
    62     connection.queries = []
    63 dispatcher.connect(reset_queries, signal=signals.request_started)
    64 
    6559# Register an event that rolls back the connection
    6660# when a Django request has an exception.
    6761def _rollback_on_exception():
    6862    from django.db import transaction
    6963    transaction.rollback_unless_managed()
    70 dispatcher.connect(_rollback_on_exception, signal=signals.got_request_exception)
     64dispatcher.connect(_rollback_on_exception, signal=core_signals.got_request_exception)
  • django/db/signals.py

     
     1query_execute = object()
  • django/db/backends/util.py

     
    11import datetime
     2from django.db import signals
     3from django.dispatch import dispatcher
    24import md5
    35from time import time
    46
     
    79except ImportError:
    810    from django.utils import _decimal as decimal    # for Python 2.3
    911
    10 class CursorDebugWrapper(object):
     12class CursorSignalWrapper(object):
    1113    def __init__(self, cursor, db):
    1214        self.cursor = cursor
    1315        self.db = db # Instance of a BaseDatabaseWrapper subclass
     
    1820            return self.cursor.execute(sql, params)
    1921        finally:
    2022            stop = time()
    21             sql = self.db.ops.last_executed_query(self.cursor, sql, params)
    22             self.db.queries.append({
    23                 'sql': sql,
    24                 'time': "%.3f" % (stop - start),
    25             })
     23            dispatcher.send(signal=signals.query_execute, sender=self, sql=sql, params=params, time=stop-start)
    2624
    2725    def executemany(self, sql, param_list):
    2826        start = time()
     
    3028            return self.cursor.executemany(sql, param_list)
    3129        finally:
    3230            stop = time()
    33             self.db.queries.append({
    34                 'sql': '%s times: %s' % (len(param_list), sql),
    35                 'time': "%.3f" % (stop - start),
    36             })
     31            # XXX: Should this be a special signal that only gets called once for efficiency?
     32            for params in param_list:
     33                dispatcher.send(signal=signals.query_execute, sender=self, sql=sql, params=params, time=stop-start)
    3734
    3835    def __getattr__(self, attr):
    3936        if attr in self.__dict__:
     
    4138        else:
    4239            return getattr(self.cursor, attr)
    4340
     41
    4442###############################################
    4543# Converters from database (string) to Python #
    4644###############################################
  • django/db/backends/__init__.py

     
    1212    ops = None
    1313    def __init__(self, **kwargs):
    1414        self.connection = None
    15         self.queries = []
    1615        self.options = kwargs
    1716
    1817    def _commit(self):
     
    3130    def cursor(self):
    3231        from django.conf import settings
    3332        cursor = self._cursor(settings)
    34         if settings.DEBUG:
    35             return self.make_debug_cursor(cursor)
     33        from django.db.backends import util
     34        cursor = util.CursorSignalWrapper(cursor, self)
    3635        return cursor
    3736
    38     def make_debug_cursor(self, cursor):
    39         from django.db.backends import util
    40         return util.CursorDebugWrapper(cursor, self)
    41 
    4237class BaseDatabaseFeatures(object):
    4338    allows_group_by_ordinal = True
    4439    allows_unique_and_pk = True
  • django/core/context_processors.py

     
    3333    context_extras = {}
    3434    if settings.DEBUG and request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS:
    3535        context_extras['debug'] = True
    36         from django.db import connection
    37         context_extras['sql_queries'] = connection.queries
    3836    return context_extras
    3937
    4038def i18n(request):
  • tests/modeltests/select_related/models.py

     
    77the select-related behavior will traverse.
    88"""
    99
    10 from django.db import models
     10from django.db import models, signals
     11from django.dispatch import dispatcher
    1112
    1213# Who remembers high school biology?
    1314
     
    7576        obj.save()
    7677        parent = obj
    7778
     79class 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
     91def track_query(sender, *args, **kwargs):
     92    QueryCounter.add()
     93dispatcher.connect(track_query, signal=signals.query_execute, weak=False)
     94
    7895__test__ = {'API_TESTS':"""
    7996
    80 # Set up.
    81 # The test runner sets settings.DEBUG to False, but we want to gather queries
    82 # so we'll set it to True here and reset it at the end of the test suite.
    83 >>> from django.conf import settings
    84 >>> settings.DEBUG = True
    85 
    8697>>> create_tree("Eukaryota Animalia Anthropoda Insecta Diptera Drosophilidae Drosophila melanogaster")
    8798>>> create_tree("Eukaryota Animalia Chordata Mammalia Primates Hominidae Homo sapiens")
    8899>>> create_tree("Eukaryota Plantae Magnoliophyta Magnoliopsida Fabales Fabaceae Pisum sativum")
     
    91102>>> from django import db
    92103
    93104# Normally, accessing FKs doesn't fill in related objects:
    94 >>> db.reset_queries()
     105>>> QueryCounter.clear()
    95106>>> fly = Species.objects.get(name="melanogaster")
    96107>>> fly.genus.family.order.klass.phylum.kingdom.domain
    97108<Domain: Eukaryota>
    98 >>> len(db.connection.queries)
     109>>> QueryCounter.counter
    991108
    100111
    101112# However, a select_related() call will fill in those related objects without any extra queries:
    102 >>> db.reset_queries()
     113>>> QueryCounter.clear()
    103114>>> person = Species.objects.select_related().get(name="sapiens")
    104115>>> person.genus.family.order.klass.phylum.kingdom.domain
    105116<Domain: Eukaryota>
    106 >>> len(db.connection.queries)
     117>>> QueryCounter.counter
    1071181
    108119
    109120# select_related() also of course applies to entire lists, not just items.
    110121# Without select_related()
    111 >>> db.reset_queries()
     122>>> QueryCounter.clear()
    112123>>> world = Species.objects.all()
    113124>>> [o.genus.family for o in world]
    114125[<Family: Drosophilidae>, <Family: Hominidae>, <Family: Fabaceae>, <Family: Amanitacae>]
    115 >>> len(db.connection.queries)
     126>>> QueryCounter.counter
    1161279
    117128
    118129# With select_related():
    119 >>> db.reset_queries()
     130>>> QueryCounter.clear()
    120131>>> world = Species.objects.all().select_related()
    121132>>> [o.genus.family for o in world]
    122133[<Family: Drosophilidae>, <Family: Hominidae>, <Family: Fabaceae>, <Family: Amanitacae>]
    123 >>> len(db.connection.queries)
     134>>> QueryCounter.counter
    1241351
    125136
    126137# The "depth" argument to select_related() will stop the descent at a particular level:
    127 >>> db.reset_queries()
     138>>> QueryCounter.clear()
    128139>>> pea = Species.objects.select_related(depth=1).get(name="sativum")
    129140>>> pea.genus.family.order.klass.phylum.kingdom.domain
    130141<Domain: Eukaryota>
    131142
    132143# Notice: one few query than above because of depth=1
    133 >>> len(db.connection.queries)
     144>>> QueryCounter.counter
    1341457
    135146
    136 >>> db.reset_queries()
     147>>> QueryCounter.clear()
    137148>>> pea = Species.objects.select_related(depth=5).get(name="sativum")
    138149>>> pea.genus.family.order.klass.phylum.kingdom.domain
    139150<Domain: Eukaryota>
    140 >>> len(db.connection.queries)
     151>>> QueryCounter.counter
    1411523
    142153
    143 >>> db.reset_queries()
     154>>> QueryCounter.clear()
    144155>>> world = Species.objects.all().select_related(depth=2)
    145156>>> [o.genus.family.order for o in world]
    146157[<Order: Diptera>, <Order: Primates>, <Order: Fabales>, <Order: Agaricales>]
    147 >>> len(db.connection.queries)
     158>>> QueryCounter.counter
    1481595
    149 
    150 # Reset DEBUG to where we found it.
    151 >>> settings.DEBUG = False
    152160"""}
Back to Top