Effective use of class_prepared signal

231 views
Skip to first unread message

Benjamin Slavin

unread,
Oct 3, 2007, 11:23:15 AM10/3/07
to django...@googlegroups.com
Hello all,

I'm trying to make use of the class_prepared signal to add some
functionality to all models.

The problem I'm facing is how to properly register my listener.

I need to register the listener before any models are prepared, but I
can't seem to figure out how to accomplish this.

Right now I have it registered in __init__.py in my application, and
put that application first in my settings module.

This works in the shell because of a work-around for #1796 that forces
loading of all models through get_models (a work-around which,
perhaps, should be removed since #1796 was fixed). This work-around
isn't present in the mod_python or wsgi handlers, so this approach
doesn't work for non-interactive (shell) sessions.

Any assistance/ideas would be appreciated.

Thanks,
- Ben

Malcolm Tredinnick

unread,
Oct 3, 2007, 11:38:24 AM10/3/07
to django...@googlegroups.com
On Wed, 2007-10-03 at 11:23 -0400, Benjamin Slavin wrote:
> Hello all,
>
> I'm trying to make use of the class_prepared signal to add some
> functionality to all models.
>
> The problem I'm facing is how to properly register my listener.
>
> I need to register the listener before any models are prepared, but I
> can't seem to figure out how to accomplish this.
>
> Right now I have it registered in __init__.py in my application, and
> put that application first in my settings module.

The only thing that is really guaranteed to be loaded sufficiently early
in the process is the settings module (along with the __init__.py file
in the directory containing settings.py). So one solution is to place
the hook loading in there.

Now, it's possible/probable you don't want to do anything really
complicated in settings.py, particularly if what you want to do would
rely upon the settings. Since that module is still being imported when
your code is executed, you have to be a little careful. For simple
things, particularly code that doesn't rely on settings, you're fine:
just install your method immediately.

For more complex cases, install an initial method that works out whether
it has been called before or not and replaces itself with the real
method on the first call (registers the "real handler" and deregisters
itself, for example).

Another solution is to subclass the handler for the types of request you
are doing (modpython or wsgi) and install your hooks as part of the
request processing in the subclass.

Neither of these solutions would work if you were wanting to do this as
a third-party app, since both intrude on the setup of the user. However,
in this case, there is no reliable way to ensure your code is run
sufficiently early. There might be an argument for putting a hook in all
the handlers (and the interactive shell setup in django-admin.py) to
call a Python function that you specify in your settings file. That
would allow use to do any pre-runtime setup in a portable fashion. If
there's not some obvious reason why this is a bad idea, you might like
to open a ticket for this. I can't immediately think of any slippery
slope to doom that this would open up and I can think of some situations
where it would be useful.

> This works in the shell because of a work-around for #1796 that forces
> loading of all models through get_models (a work-around which,
> perhaps, should be removed since #1796 was fixed). This work-around
> isn't present in the mod_python or wsgi handlers, so this approach
> doesn't work for non-interactive (shell) sessions.

The workaround will be removed eventually. I didn't remove it
immediately in case the last round of fixes to #1796 didn't completely
work -- people would have wanted the workaround put back immediately and
I didn't want the hassle for myself or the user base. It's harmless in
any case, so not a really high priority.

Regards,
Malcolm

Benjamin Slavin

unread,
Oct 3, 2007, 12:47:46 PM10/3/07
to django...@googlegroups.com
Malcolm,

As always, your expedient and thoughtful reply is appreciated.

On 10/3/07, Malcolm Tredinnick <mal...@pointy-stick.com> wrote:
> The only thing that is really guaranteed to be loaded sufficiently early
> in the process is the settings module (along with the __init__.py file
> in the directory containing settings.py). So one solution is to place
> the hook loading in there.

This was my first thought, but it feels very hackish. As you point
out, there are reasons why this is not desirable (dependence on
settings and portability of the app).


> Another solution is to subclass the handler for the types of request you
> are doing (modpython or wsgi) and install your hooks as part of the
> request processing in the subclass.

This is certainly a possibility, but again it doesn't feel right.


> [...] in this case, there is no reliable way to ensure your code is run
> sufficiently early.

Thus, my question :-)

> There might be an argument for putting a hook in all
> the handlers (and the interactive shell setup in django-admin.py) to
> call a Python function that you specify in your settings file. That
> would allow use to do any pre-runtime setup in a portable fashion.

I like the direction of this approach, and think it is worth looking
into further. I assume that your vision is for an iterable object
like MIDDLEWARE_CLASSES that can specify multiple pre-runtime
functions?

I'd be happy to file a ticket and provide a patch (assuming there's no
nastiness I'm overlooking). I'll bring this up on django-dev once I
have the ticket and patch in place.


> The workaround [for the management shell] will be removed eventually
> [...] It's harmless in any case, so not a really high priority.

Understood. I've tested it without the work-around, and have had no
problems (other than the one discussed here).


Many thanks,
- Ben

Reply all
Reply to author
Forward
0 new messages