tags:

views:

487

answers:

2

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?

+1  A: 

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.

Jarret Hardie
Haven't thought of that. I only tested it with ONE project :)
Andrei Taranchenko
+4  A: 

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.

David Berger
David, the middleware solutions looks pretty interesting but, if I may, I found only one caveat with it - if you have manage.py custom commands that need access to the settings, getting the settings overrides will most likely prove difficult. Keeping your answer in mind, I went with setting the overrides on each request, from something such as [PREFIX]_MEDIA_ROOT. This allows me to write manage.py commands that don't rely on any trickery.
Andrei Taranchenko
That should work. Name mangling isn't always recommended style. You may consider combining this with your original solution: have a single MEDIA_ROOT, then in project1/__init__.py, create an arbitrary conf variable, such as settings.PROJECT_NAME = "project1". Then your view logic can refer to request.media_root and you manage.py functions can reconstruct a path from settings.MEDIA_ROOT and settings.PROJECT_NAME.
David Berger