The global state problem is something that's been bothering me for a long 
while, but after seeing a presentation of Alex Gaynor [1] from last year, I 
started thinking about this again.

The main problem is that you'd need to have a DjangoProject object which 
contains the root configuration and you'd have to somehow pass that object 
around everywhere.

Maybe I'm not the first to think about this, but what's wrong with 
thread-local-storage? In Django, we have a huge advantage above nodejs in 
that there's only one active request per thread and that request should 
belong to only one DjangoProject instance. (We don't have unexpected 
contextswitches in the same thread, like in Twisted or Tulip. -- We can 
make that assumption.)

Actually we are already using threadlocals for the current active language 
[2], so I don't see any reason for not using the same approach to keep 
track of the currently active DjangoApplication object.

It's not a really small project, but not impossible huge either. The most 
important parts of the code that need to be changed to use this thread 
local are:

* django.conf.settings:
We don't want to break that API, so the settings object should become a 
proxy that knows the current active project and returns the correct 
settings.

* the reverse() functions (and a few others) from URL patterns.
URL patterns depend on the application.

* Django models:
That's the harder one. MyModel.objects.get() needs to know the settings, in 
order to know what the current database is.


I would propose a python context manager to move from one project to 
another, if you ever have to. Say that you want to query a model from 
another project, you can do this:

other_django_project = DjangoProject.from_settings_file(my_project_settings)
with other_django_project.activate():
    MyModel.objects.get()

manage.py should look like this:

if __name__ == '__main__':
    django_project = DjangoProject.from_settings_file(my_project_settings)
    with django_project.activate():
        execute_from_command_line(sys.argv)


And for the flask-lovers which don't like automatic code generation and 
singleton patterns, they can just use the DangoProject constructor:

if __name__ == '__main__':
    django_project = DjangoProject(
            url_patterns=root_url_patterns,
            installed_apps=[ ... ],
            ....
    )
    with django_project.activate():
        execute_from_command_line(sys.argv)


For the why of all this, I refer to the presentation of Alex, but the main 
advantages are that it becomes much more easy to integrate Django projects 
in other Python projects and that unit testing becomes easier: you don't 
have a global state.

What do you think? I don't see real backward-compatibility issues that we 
can't solve. Do I forget something?

Cheers,
Jonathan


[1] https://www.youtube.com/watch?v=0FD510Oz2e4
[2] 
https://github.com/django/django/blob/master/django/utils/translation/trans_real.py#L23

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/7dd166af-f8d6-4838-9a34-480ef5e5581c%40googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to