Andrei Taranchenko
Andrei Taranchenko

Reputation: 1304

Best way to override global settings in Django

I have a Django project with multiple applications (say, two), and both need different versions of MEDIA_ROOT and MEDIA_URL.

The documentation does specify how to modify a specific setting, but here is what I did.

I created a project1/settings.py,

# project1/settings.py, 
from django.conf import settings

settings.MEDIA_URL = 'foo'
settings.MEDIA_ROOT = 'bar'

Then I modified the init module of that application to only load the module:

# project1/__init__.py
import settings

It works! The specialized settings file happily overwrites the global one, selectively. What I like about this is that the project settings file is in a logical location.

My question is - does this approach have any caveats, and what is the best practices way to achieve this?

Upvotes: 1

Views: 4516

Answers (2)

David Berger
David Berger

Reputation: 12803

Jarret is right. Best case scenario: this will work if you run a very simple test after restarting the server. Just about anything else will break it.

If you're just using MEDIA_* as constants, I'd recommend using some other constant. If you really are using them for default upload settings for file fields, it sounds like your project is going to require you to specify the path. That shouldn't be too hard.

There are two problems you need to overcome that your current scheme doesn't address:

  1. Dynamically setting variables every time a request is made
  2. Avoiding bad race conditions

1 is best accomplished through custom MiddleWare, probably with a process_request method. What you want to avoid, however, is the

settings.MEDIA_URL = 'foo'

global variable abuse. That will bring up problem 2. Since process_request lets you pass around an HttpRequest object, I recommend putting the variable information there:

class MyMiddleWare:
    def process_request(self,request):
        media_root = #some logic to parse request.path
        request.media_root = media_root

Your static links will then have to make refer to request.media_root.

Upvotes: 4

Jarret Hardie
Jarret Hardie

Reputation: 98022

I'm a bit confused by how this is supposed to work. How will you use the settings in each application's code?

# project1/view.py
import settings
print settings.MEDIA_URL

or

# project1/view.py
from django.conf import settings
print settings.MEDIA_URL

In first case, that probably won't work since the settings you're importing is project1.settings, which itself has no MEDIA_URL attribute.

In the second case, won't you end up with a race condition? Whichever application was loaded last will have last overwritten the attribute in the global settings object. This may work in some cases where you are just running locally and you start the server, then go immediately to a view in one or other of the applications, but in a long running server like Apache which keeps several child processes bootstrapped and running, re-using them from request-to-request, the values in your settings will be unpredictable. Remember that the code in your init will be processed only when it is imported for the first time... subsequent imports do not cause the code to re-run.

Maybe I'm missing something in your description.

If you have application-specific settings, you'll need to have your own app-specific settings and code your logic to use them as appropriate.

Upvotes: 2

Related Questions