26

When you install a new django application, you have to add/modify your settings.py module.

For a project I'm trying to make that module a python subpackage and create a module for each application:

settings\
    __init__.py
    base.py
    admin.py
    feincms.py
    ...

The problem I'm confronted with is how to merge settings.py attributes (INSTALLED_APPS for example is a tuple of values) that are getting values in the different submodules?

Thanks


Ok, I asked the wrong question (got the right answer for it though). My question should have been, how to get attributes from all submodules and merge them? Django will import settings and expects everything to be there.

victor n.
  • 658
  • 1
  • 7
  • 14

8 Answers8

8

"When you install a new django application, you have to add/modify your settings.py module."

I think this is fine as is.

I don't see any reason to change or modify this at all.

What we do, however, is to "subclass" the core settings module.

Our developer-specific and installation-specific files have names like settings_devxy_linux2 and settings_checkout_win32, etc.

Each of these files starts with from settings import * to import the core settings and extend those core settings with overrides for a specific installation and platform.

It doesn't require any real work. It does, however, mean that we do most things with django-admin.py because our settings aren't called settings.

S.Lott
  • 384,516
  • 81
  • 508
  • 779
  • So, are these the files you specify in `DJANGO_SETTINGS_MODULE` in the environment? We went sort of the opposite direction: we have `settings.py` but it does a try/include of local_early_setting.py and of local_late_settings.py. These files differ from development to staging. The basic `settings.py` contains the correct production values. – Peter Rowell Jan 10 '10 at 02:08
  • We specify `settings_prod_linux2` for production; it imports the core `settings` that define the project as a whole. I use `settings_devsl_win32` for development; it imports the core `settings`. Since it's simple overrides, there's no "logic". No "if", no "try". – S.Lott Jan 10 '10 at 02:26
  • Good point. We had to explicitly exclude our local*settings files from Mercurial so they didn't accidentally end up in production. Thanx for the idea. – Peter Rowell Jan 10 '10 at 03:39
  • 2
    Peter's plan suffers from the problem of the original question: imported modules can't easily e.g. add items to `INSTALLED_APPS`. – akaihola Jan 18 '10 at 14:35
7

You might be interested in this solution; uses execfile() to load a series of settings files in order, where each file has full access to settings from previously-loaded files, to update, modify, etc.

Carl Meyer
  • 122,012
  • 20
  • 106
  • 116
  • yes, i ended up writing a solution similar to that. but execfile() is now discouraged. so i used exec() and compile() – victor n. Jan 10 '10 at 11:02
  • 9
    victor, it would be interesting to see the code for your solution – akaihola Jan 18 '10 at 14:37
  • so sorry guys. that was like 3 years ago and i don't remember the app i was working on. but this answer might help: http://stackoverflow.com/a/437857/125560. also be sure to be up to date with these things. i am seeing that there are a few other alternatives for Python3 – victor n. Dec 27 '13 at 16:49
6

I've used this work-around:

settings.py:

INSTALLED_APPS = ('whatever',)
import more_settings
more_settings.modify(globals())

more_settings.py:

def modify(settings):
    settings['INSTALLED_APPS'] += ('another_app',)
akaihola
  • 26,309
  • 7
  • 59
  • 69
3

I created https://code.djangoproject.com/wiki/SplitSettings#SettingInheritancewithHierarchy as my preferred solution. Allows for inheritance from a common file in any deployment environment.

2

I have the same structure of settings files and I do the following to import the settings of the submodules:

def load_settings_file(file):
    file = open(os.path.join(INSTALL_DIR, '<projectname>', 'settings', file + '.py'))
    content = file.read()
    file.close()
    return content

for submodule in ['base', 'admin', 'feincms']:
    exec(load_settings_file(submodule))
dArignac
  • 1,205
  • 4
  • 11
  • 25
1

If you prefer more magic than in my previous more_settings.modify() approach, try this:

settings.py:

INSTALLED_APPS = ('whatever',)
import more_settings
more_settings.modify(globals())

more_settings.py:

def config(INSTALLED_APPS=(), **other_settings):
    INSTALLED_APPS += ('another_app',)
    del other_settings
    return locals()

def modify(settings):
    settings.update(config(**settings))

Pros: no need to refer to settings with dict notation

Cons: must define modified settings as kwargs for config()

akaihola
  • 26,309
  • 7
  • 59
  • 69
0

Presumably the best way to "merge" varies, attributes by attributes. For example, given several tuples (from the INSTALLED_APPS of various submodules), you might simply concatenate them into a new tuple (for the INSTALLED_APPS attribute of the package as a whole), or, if possible duplications are a problem, so something smarter to remove the duplications (in this case you may not care about ordering, so simply tuple(set(tup1+tup2+tup3)) might suffice).

For other cases ("merging" dictionaries, "merging" settings which are just scalars or strings, etc) you'll need different strategies (maybe successive .update calls for the dictionaries, pick just one according to some criteria for the scalars or strings, etc, etc) -- I just don't see a "one size fits all" approach working here.

Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
-1

just put

from base import *
from admin import *
...

in ur init.py that should work

i used it for different sites

base/settings.py # common settings: db, apps, ...
base/sites/website1/settings.py # site_id, custom middleware 
base/sites/website2/settings.py # site_id, custom middleware

the website settings import the common settings with

from base.settings import *

and define custom attribtues

mo.
  • 3,474
  • 1
  • 23
  • 20