On Sun, Jul 15, 2012 at 11:07 AM, Jeremy Dunck <
jdu...@gmail.com> wrote:
>
> That is indeed what I meant, but I think Anssi's probably right that
> this belongs in contribute_to_class instead of a new adhoc thing in
> ModelBase.__new__.
>
> I'll take a swing at making this change.
>
> Opened related ticket:
https://code.djangoproject.com/ticket/18627
OK, I have a very rough cut w/ all tests passing here:
https://github.com/jdunck/django/tree/18627_pre_init
I poked in a flag, sys.JDUNCK_NEW, which can be turned on/off for old
and new implementation - this is poked in at django.__init__
To test performance, using tests/test_sqlite modified with:
INSTALLED_APPS = [
'regressiontests.model_fields'
]
and
DATABASES['default']['name'] = ':memory:'
Testing the pre_init hook:
timeit.Timer("""
for i in names:
models.Person(name=i)
""", """
from django.core.management import call_command
from regressiontests.model_fields import models
call_command('syncdb')
names = [str(i) for i in range(1000)]
""").timeit(1000)
Under the existing signal usage: 24.609718084335327
Under the new approach avoiding signal usage: 18.074234008789062
I'd expect post_init to be a smaller gain since the destination
function has more overhead, but still a gain.
Note that the pre_init and post_init signals are still fired -- it's
just that django as-shipped won't use any listeners on them, so the
Model.__init__ performance improves.
In some cases, object construction currently is larger than query time
- a simple 'select x from y limit 1000' would have similar overhead to
this. Also, note that this gain would be seen on all models in any
project using GFK or ImageField but no other pre_init or post_init
hooks - not just those models which have the fields. With this
switch, only the models with the hooking fields have the related
overhead.
Feedback welcome.