Ticket #16639: obj-creation-speed.diff
File obj-creation-speed.diff, 7.1 KB (added by , 13 years ago) |
---|
-
django/db/models/base.py
diff --git a/django/db/models/base.py b/django/db/models/base.py index 71fd1f7..3e770fc 100644
a b class Model(object): 277 277 _deferred = False 278 278 279 279 def __init__(self, *args, **kwargs): 280 signals.pre_init.send(sender=self.__class__, args=args, kwargs=kwargs)281 280 if self._meta.has_pre_init_listeners or signals.pre_init.has_global_listeners: 281 signals.pre_init.send(sender=self.__class__, args=args, kwargs=kwargs) 282 282 # Set up the storage for instance state 283 283 self._state = ModelState() 284 284 … … class Model(object): 367 367 if kwargs: 368 368 raise TypeError("'%s' is an invalid keyword argument for this function" % kwargs.keys()[0]) 369 369 super(Model, self).__init__() 370 signals.post_init.send(sender=self.__class__, instance=self) 370 if self._meta.has_post_init_listeners or signals.post_init.has_global_listeners: 371 signals.post_init.send(sender=self.__class__, instance=self) 371 372 372 373 def __repr__(self): 373 374 try: -
django/db/models/options.py
diff --git a/django/db/models/options.py b/django/db/models/options.py index 6f0f406..fc13cee 100644
a b class Options(object): 54 54 # from *other* models. Needed for some admin checks. Internal use only. 55 55 self.related_fkey_lookups = [] 56 56 57 # These variables are here to make it possible to skip pre_init 58 # and post_init signals when there are no listeners for the model. 59 # This can save up to 2/3 of the time used in Model __init__. 60 # The variables are set by pre_init's and post_init's connect methods. 61 self.has_pre_init_listeners = False 62 self.has_post_init_listeners = False 63 57 64 def contribute_to_class(self, cls, name): 58 65 from django.db import connection 59 66 from django.db.backends.util import truncate_name -
django/db/models/signals.py
diff --git a/django/db/models/signals.py b/django/db/models/signals.py index 48872e7..5b9065b 100644
a b from django.dispatch import Signal 2 2 3 3 class_prepared = Signal(providing_args=["class"]) 4 4 5 pre_init = Signal(providing_args=["instance", "args", "kwargs"]) 6 post_init = Signal(providing_args=["instance"]) 5 # Pre and post init signals have subclasses with some optimizations. The subclass 6 # connect methods make sure that Model __init__ knows about somebody listening. We 7 # don't want to pay the overhead of sending these signals if nobody is listening, as 8 # model initialization is a common operation. 9 class PreInitSignal(Signal): 10 has_global_listeners = False 11 def connect(self, *args, **kwargs): 12 if 'sender' in kwargs: 13 kwargs['sender']._meta.has_pre_init_listeners = True 14 else: 15 self.has_global_listeners = True 16 return super(PreInitSignal, self).connect(*args, **kwargs) 17 18 class PostInitSignal(Signal): 19 has_global_listeners = False 20 def connect(self, *args, **kwargs): 21 if 'sender' in kwargs: 22 kwargs['sender']._meta.has_post_init_listeners = True 23 else: 24 self.has_global_listeners = True 25 return super(PostInitSignal, self).connect(*args, **kwargs) 26 27 pre_init = PreInitSignal(providing_args=["instance", "args", "kwargs"]) 28 post_init = PostInitSignal(providing_args=["instance"]) 7 29 8 30 pre_save = Signal(providing_args=["instance", "raw", "using"]) 9 31 post_save = Signal(providing_args=["instance", "raw", "created", "using"]) -
tests/modeltests/signals/tests.py
diff --git a/tests/modeltests/signals/tests.py b/tests/modeltests/signals/tests.py index 9b8bce0..5503786 100644
a b class SignalTests(TestCase): 29 29 # Save up the number of connected signals so that we can check at the 30 30 # end that all the signals we register get properly unregistered (#9989) 31 31 pre_signals = ( 32 len(signals.pre_init.receivers), 33 len(signals.post_init.receivers), 32 34 len(signals.pre_save.receivers), 33 35 len(signals.post_save.receivers), 34 36 len(signals.pre_delete.receivers), … … class SignalTests(TestCase): 67 69 def pre_save_decorator_sender_test(signal, sender, instance, **kwargs): 68 70 data.append(instance) 69 71 72 def pre_init_test(signal, sender, **kwargs): 73 data.append(sender) 74 signals.pre_init.connect(pre_init_test, sender=Person) 75 76 def post_init_test(signal, sender, instance, **kwargs): 77 data.append((instance, instance.pk is None)) 78 signals.post_init.connect(post_init_test, sender=Person) 79 80 def pre_init_all_models_test(signal, sender, **kwargs): 81 data.append((sender, 'GLOBAL')) 82 signals.pre_init.connect(pre_init_all_models_test) 83 70 84 p1 = Person(first_name="John", last_name="Smith") 71 self.assertEqual(data, []) 85 self.assertEqual(data, [Person, (Person, 'GLOBAL'), (p1, True)]) 86 data[:] = [] 72 87 p1.save() 73 88 self.assertEqual(data, [ 74 89 (p1, False), … … class SignalTests(TestCase): 88 103 89 104 # Car signal (sender defined) 90 105 c1 = Car(make="Volkswagon", model="Passat") 106 self.assertEqual(data, [(Car, 'GLOBAL')]) 107 data[:] = [] 91 108 c1.save() 92 109 self.assertEqual(data, [ 93 110 (c1, False), … … class SignalTests(TestCase): 114 131 data[:] = [] 115 132 116 133 p2 = Person(first_name="James", last_name="Jones") 134 self.assertEqual(data, [Person, (Person, 'GLOBAL'), (p2, True)]) 135 data[:] = [] 117 136 p2.id = 99999 118 137 p2.save() 119 138 self.assertEqual(data, [ … … class SignalTests(TestCase): 137 156 (p2, False), 138 157 (p2, False) 139 158 ]) 159 data[:] = [] 160 161 p3 = Person.objects.all()[0] 162 self.assertEqual(data, [Person, (Person, 'GLOBAL'), (p3, False)]) 163 data = data[:] 140 164 141 165 self.assertQuerysetEqual( 142 166 Person.objects.all(), [ … … class SignalTests(TestCase): 145 169 unicode 146 170 ) 147 171 172 signals.pre_init.disconnect(pre_init_test, sender=Person) 173 signals.pre_init.disconnect(pre_init_all_models_test) 174 # We need to do a dirty trick here - connecting to a global pre or post init 175 # signal sets a state for the whole Django project - we want to get rid of 176 # that state. 177 signals.pre_init.has_global_listeners = False 178 signals.post_init.disconnect(post_init_test, sender=Person) 148 179 signals.post_delete.disconnect(post_delete_test) 149 180 signals.pre_delete.disconnect(pre_delete_test) 150 181 signals.post_save.disconnect(post_save_test) … … class SignalTests(TestCase): 154 185 155 186 # Check that all our signals got disconnected properly. 156 187 post_signals = ( 188 len(signals.pre_init.receivers), 189 len(signals.post_init.receivers), 157 190 len(signals.pre_save.receivers), 158 191 len(signals.post_save.receivers), 159 192 len(signals.pre_delete.receivers),