Project path

69 views
Skip to first unread message

Lachlan Musicman

unread,
Dec 10, 2012, 8:59:14 PM12/10/12
to django...@googlegroups.com
Hola,

I've got a split settings set up for my prod/dev sites, and in all the
hints I've seen over the years, I've most appreciated the line at the
top of the settings file that goes like this (there are variations to
the theme):

BASE_DIR = os.path.dirname(os.path.abspath(__file__))

But almost all of the docs that I grab this info from are pre
Django1.4, and I believe it was 1.4 where the structure changed
slightly - settings are now in

path/proj/proj/settings.py
path/proj/app1
path/proj/app2

I would like BASE_DIR to be path/proj/ so I can use it in
STATICFILES_DIRS for instance, but it's coming out as path/proj/proj/

I am thinking about:

SETTINGS_DIR = os.path.dirname(os.path.abspath(__file__))
BASE_DIR = os.path.join(SETTINGS_DIR, '..')

But it seems a bit convoluted or horrible.

Does anyone have a better solution they could share?

cheers
L.


--
...we look at the present day through a rear-view mirror. This is
something Marshall McLuhan said back in the Sixties, when the world
was in the grip of authentic-seeming future narratives. He said, “We
look at the present through a rear-view mirror. We march backwards
into the future.”

http://www.warrenellis.com/?p=14314

Bill Freeman

unread,
Dec 11, 2012, 11:25:40 AM12/11/12
to django...@googlegroups.com
On Mon, Dec 10, 2012 at 8:59 PM, Lachlan Musicman <dat...@gmail.com> wrote:
Hola,

I've got a split settings set up for my prod/dev sites, and in all the
hints I've  seen over the years, I've most appreciated the line at the
top of the settings file that goes like this (there are variations to
the theme):

BASE_DIR = os.path.dirname(os.path.abspath(__file__))

But almost all of the docs that I grab this info from are pre
Django1.4, and I believe it was 1.4 where the structure changed
slightly - settings are now in

path/proj/proj/settings.py
path/proj/app1
path/proj/app2

I would like BASE_DIR to be path/proj/ so I can use it in
STATICFILES_DIRS for instance, but it's coming out as path/proj/proj/

I am thinking about:

SETTINGS_DIR = os.path.dirname(os.path.abspath(__file__))
BASE_DIR = os.path.join(SETTINGS_DIR, '..')

But it seems a bit convoluted or horrible.

Does anyone have a better solution they could share?

cheers
L.

First stuff you almost certainly already know, so we're using the same terminology.  In pre-1.4 it was the directory containing the settings.py file that had to be on sys.path in order to be able to have custom apps installed there and to be able to reference them without using the project name.  (If you weren't going have things imported that way, it didn't have to be on the path, but this only shows up for mod_wsgi deployments, since cd'ing to that directory to run a management command like runserver automatically causes python to add this directory.)  When run from manage.py, Django did a trick of temporarily adding the parent directory to sys.path, importing proj.settings, then removing the parent from sys.path.  For this to work, there had to be an __init__.py file in the settings.py directory (still does), making it a package.  This took advantage of the fact that once a package is imported, it no longer needs to be on the path to import its contents, allowing, for example, importing prog.urls among other things, but without littering your top level namespace with any other modules or packages that happened to be in the parrent directory.

In 1.4 plus, there is an extra directory level, by default, duplicating the project name(*), and manage.py is moved up to the higher level, rather than sharing with settings, urls, etc.  Since this directory is on the path already (if you cd here and run python manage.py ...), no fiddling with a temporary add of the parent is needed, nor done.  The upper directory is not a package, so it doesn't need an __init__.py file.  The proj package, from which settings, urls, and wsgi can be imported, is just on the path, so these project name qualified modules load just fine.  If you want apps that aren't qualified by the project name (so that you can override ones in site-packages, or so that they are portable), start them in the upper directory.  If you want some apps that have to be qualified with the project name, start them in the lower directory.

So we have three interesting pieces of information.  The name of the project, call it PROJECT_NAME.  The path to the directory containing manage.py, call it PROJECT_ROOT.  And the path to the directory containing settings.py, SETTINGS_DIR.

    import os, django
    SETTINGS_DIR = os.path.dirname(os.path.abspath(__file__)
    PROJECT_ROOT, PROJECT_NAME = os.path.split(SETTINGS_DIR)
    if django.VERSION[:2] < (1, 4): PROJECT_ROOT = SETTINGS_DIR

I typically define some functions with short names here, typically _m, _r and _s, that perform string join with '.' or os.path.join of their arguments onto PROJECT_NAME, PROJECT_ROOT, and SETTINGS_DIR respectively, allowing me to say things like:

    ROOT_URLCONF = _m('urls')
    TEMPLATE_DIRS = (_r('templates'),)

etc.  (I actually haven't found a need for _s, and usually don't define it).

[* Note that the name of the upper directory doesn't matter.  You can rename it, cd back in, and the manage.py commands all still work.  If, however, you have deployed with, say, mod_wsgi, you will have to tell it's configuration files about the change.  The approaches above can keep the project name out of settings.py and wsgi.py so that if you change the project name itself, you need merely rename the directory, edit manage.py, and edit any front end proxy configuration that has absolute paths, such as for mod_wsgi.]

I had put this stuff into a package that I could install in site-packages, and which had a singleton instance of a class initialized by passing it your __file__, but never got around to releasing it.

Bill

Lachlan Musicman

unread,
Dec 11, 2012, 4:11:46 PM12/11/12
to django...@googlegroups.com
I don't think I've ever got a more comprehensive and excellent response - cheers
L.
> --
> You received this message because you are subscribed to the Google Groups
> "Django users" group.
> To post to this group, send email to django...@googlegroups.com.
> To unsubscribe from this group, send email to
> django-users...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/django-users?hl=en.

Chris Cogdon

unread,
Dec 12, 2012, 4:32:18 PM12/12/12
to django...@googlegroups.com
Not sure if you're willing to consider an alternate, here, but this is a issue Iv'e gone through a lot, and came up with my own solution. The major issue is that I not only want to change the top level paths, but also need to change database targets and a few other settings, between all the different dev/beta/production sites AND to make sure that the majority of my settings can be checked into our SCM. Here's what I came up with.

Rename settings to common_settings.py

Have a local_settings.py that is NOT checked into the SCM (perhaps provide a local_settings.py.example containing the minimum settings that need to be changed).

local_settings.py contains:

from projectname.common_settings import *

DATABASES = ...
SECRET_KEY = ...
STATIC_ROOT = ...

and anything else that _must_ change between installations.

Then change manage.py and wsgi.py so that it loads "common_settings" rather than "projectname.settings"

and done.

The BIG advantage here is that you're not checking anything into the SCM that must remain secret, or must change (or very likely to change) between installations, but all other settings are source controlled.

Although not necessary to rename settings.py, i do this to catch code that improperly imports settings, rather than django.conf.settings



Tom Evans

unread,
Dec 13, 2012, 12:43:30 PM12/13/12
to django...@googlegroups.com
On Wed, Dec 12, 2012 at 9:32 PM, Chris Cogdon <ch...@cogdon.org> wrote:
> The BIG advantage here is that you're not checking anything into the SCM
> that must remain secret, or must change (or very likely to change) between
> installations, but all other settings are source controlled.

The big disadvantage is that the configuration of your production
website instances are not in a VCS, you cannot track or merge changes
to them or their ancestors, and if a box goes kabluie, you can't
instantly re-create it. Configuration is code, code lives in a VCS.

(Our configuration files live in a separate repository to the project
or app code, and are finangled into place based upon the hostname)

Cheers

Tom

Chris Cogdon

unread,
Dec 13, 2012, 1:51:58 PM12/13/12
to django...@googlegroups.com, teva...@googlemail.com
Totally agreed... including being the separate repositories. If I check out the framework for use on my desktop I should _not_ be seeing the runtime configuration (including secrets and passwords) for the production systems, and viccyverca.
Reply all
Reply to author
Forward
0 new messages