Django

Code

Ticket #5415: db_signal_r6702.patch

File db_signal_r6702.patch, 9.1 kB (added by gav, 7 months ago)

Adds optional enable of signal classes.

  • django/db/__init__.py

    old new  
    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

    old new  
  • django/db/backends/util.py

    old new  
    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    def __iter__(self): 
     42        return iter(self.cursor) 
     43 
     44 
    4445############################################### 
    4546# Converters from database (string) to Python # 
    4647############################################### 
  • django/db/backends/__init__.py

    old new  
    1212    ops = None 
    1313    def __init__(self, **kwargs): 
    1414        self.connection = None 
    15         self.queries = [] 
    1615        self.options = kwargs 
     16        self.use_signal_cursor = None 
    1717 
    1818    def _commit(self): 
    1919        if self.connection is not None: 
     
    3131    def cursor(self): 
    3232        from django.conf import settings 
    3333        cursor = self._cursor(settings) 
    34         if settings.DEBUG: 
    35             return self.make_debug_cursor(cursor) 
     34        if self.use_signal_cursor or (self.use_signal_cursor == None and settings.DEBUG): 
     35            from django.db.backends import util 
     36            cursor = util.CursorSignalWrapper(cursor, self) 
    3637        return cursor 
     38     
    3739 
    38     def make_debug_cursor(self, cursor): 
    39         from django.db.backends import util 
    40         return util.CursorDebugWrapper(cursor, self) 
    41  
    4240class BaseDatabaseFeatures(object): 
    4341    allows_group_by_ordinal = True 
    4442    allows_unique_and_pk = True 
  • django/core/context_processors.py

    old new  
    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

    old new  
    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") 
    89100>>> create_tree("Eukaryota Fungi Basidiomycota Homobasidiomycatae Agaricales Amanitacae Amanita muscaria") 
    90101 
    91102>>> from django import db 
     103>>> db.connection.use_signal_cursor = True 
    92104 
    93105# Normally, accessing FKs doesn't fill in related objects: 
    94 >>> db.reset_queries() 
     106>>> QueryCounter.clear() 
    95107>>> fly = Species.objects.get(name="melanogaster") 
    96108>>> fly.genus.family.order.klass.phylum.kingdom.domain 
    97109<Domain: Eukaryota> 
    98 >>> len(db.connection.queries) 
     110>>> QueryCounter.counter 
    991118 
    100112 
    101113# However, a select_related() call will fill in those related objects without any extra queries: 
    102 >>> db.reset_queries() 
     114>>> QueryCounter.clear() 
    103115>>> person = Species.objects.select_related().get(name="sapiens") 
    104116>>> person.genus.family.order.klass.phylum.kingdom.domain 
    105117<Domain: Eukaryota> 
    106 >>> len(db.connection.queries) 
     118>>> QueryCounter.counter 
    1071191 
    108120 
    109121# select_related() also of course applies to entire lists, not just items. 
    110122# Without select_related() 
    111 >>> db.reset_queries() 
     123>>> QueryCounter.clear() 
    112124>>> world = Species.objects.all() 
    113125>>> [o.genus.family for o in world] 
    114126[<Family: Drosophilidae>, <Family: Hominidae>, <Family: Fabaceae>, <Family: Amanitacae>] 
    115 >>> len(db.connection.queries) 
     127>>> QueryCounter.counter 
    1161289 
    117129 
    118130# With select_related(): 
    119 >>> db.reset_queries() 
     131>>> QueryCounter.clear() 
    120132>>> world = Species.objects.all().select_related() 
    121133>>> [o.genus.family for o in world] 
    122134[<Family: Drosophilidae>, <Family: Hominidae>, <Family: Fabaceae>, <Family: Amanitacae>] 
    123 >>> len(db.connection.queries) 
     135>>> QueryCounter.counter 
    1241361 
    125137 
    126138# The "depth" argument to select_related() will stop the descent at a particular level: 
    127 >>> db.reset_queries() 
     139>>> QueryCounter.clear() 
    128140>>> pea = Species.objects.select_related(depth=1).get(name="sativum") 
    129141>>> pea.genus.family.order.klass.phylum.kingdom.domain 
    130142<Domain: Eukaryota> 
    131143 
    132144# Notice: one few query than above because of depth=1 
    133 >>> len(db.connection.queries) 
     145>>> QueryCounter.counter 
    1341467 
    135147 
    136 >>> db.reset_queries() 
     148>>> QueryCounter.clear() 
    137149>>> pea = Species.objects.select_related(depth=5).get(name="sativum") 
    138150>>> pea.genus.family.order.klass.phylum.kingdom.domain 
    139151<Domain: Eukaryota> 
    140 >>> len(db.connection.queries) 
     152>>> QueryCounter.counter 
    1411533 
    142154 
    143 >>> db.reset_queries() 
     155>>> QueryCounter.clear() 
    144156>>> world = Species.objects.all().select_related(depth=2) 
    145157>>> [o.genus.family.order for o in world] 
    146158[<Order: Diptera>, <Order: Primates>, <Order: Fabales>, <Order: Agaricales>] 
    147 >>> len(db.connection.queries) 
     159>>> QueryCounter.counter 
    1481605 
    149  
    150 # Reset DEBUG to where we found it. 
    151 >>> settings.DEBUG = False 
    152161"""}