[python] Using Python's os.path, how do I go up one directory?

I recently upgrade Django from v1.3.1 to v1.4.

In my old settings.py I have

TEMPLATE_DIRS = (
    os.path.join(os.path.dirname( __file__ ), 'templates').replace('\\', '/'),
    # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
    # Always use forward slashes, even on Windows.
    # Don't forget to use absolute paths, not relative paths.
)

This will point to /Users/hobbes3/Sites/mysite/templates, but because Django v1.4 moved the project folder to the same level as the app folders, my settings.py file is now in /Users/hobbes3/Sites/mysite/mysite/ instead of /Users/hobbes3/Sites/mysite/.

So actually my question is now twofold:

  1. How do I use os.path to look at a directory one level above from __file__. In other words, I want /Users/hobbes3/Sites/mysite/mysite/settings.py to find /Users/hobbes3/Sites/mysite/templates using relative paths.
  2. Should I be keeping the template folder (which has cross-app templates, like admin, registration, etc.) at the project /User/hobbes3/Sites/mysite level or at /User/hobbes3/Sites/mysite/mysite?

This question is related to python django

The answer is


You want exactly this:

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

This might be useful for other cases where you want to go x folders up. Just run walk_up_folder(path, 6) to go up 6 folders.

def walk_up_folder(path, depth=1):
    _cur_depth = 1        
    while _cur_depth < depth:
        path = os.path.dirname(path)
        _cur_depth += 1
    return path   

If you are using Python 3.4 or newer, a convenient way to move up multiple directories is pathlib:

from pathlib import Path

full_path = "path/to/directory"
str(Path(full_path).parents[0])  # "path/to"
str(Path(full_path).parents[1])  # "path"
str(Path(full_path).parents[2])  # "."

Of course: simply use os.chdir(..).


from os.path import dirname, realpath, join
join(dirname(realpath(dirname(__file__))), 'templates')

Update:

If you happen to "copy" settings.py through symlinking, @forivall's answer is better:

~user/
    project1/  
        mysite/
            settings.py
        templates/
            wrong.html

    project2/
        mysite/
            settings.py -> ~user/project1/settings.py
        templates/
            right.html

The method above will 'see' wrong.html while @forivall's method will see right.html

In the absense of symlinks the two answers are identical.


Personally, I'd go for the function approach

def get_parent_dir(directory):
    import os
    return os.path.dirname(directory)

current_dirs_parent = get_parent_dir(os.getcwd())

Go up a level from the work directory

import os
os.path.dirname(os.getcwd())

or from the current directory

import os
os.path.dirname('current path')

For a paranoid like me, I'd prefer this one

TEMPLATE_DIRS = (
    __file__.rsplit('/', 2)[0] + '/templates',
)

To go n folders up... run up(n)

import os

def up(n, nth_dir=os.getcwd()):
    while n != 0:
        nth_dir = os.path.dirname(nth_dir)
        n -= 1
    return nth_dir

I think the easiest thing to do is just to reuse dirname() So you can call

os.path.dirname(os.path.dirname( __file__ ))

if you file is at /Users/hobbes3/Sites/mysite/templates/method.py

This will return "/Users/hobbes3/Sites/mysite"


With using os.path we can go one directory up like that

one_directory_up_path = os.path.dirname('.')

also after finding the directory you want you can join with other file/directory path

other_image_path = os.path.join(one_directory_up_path, 'other.jpg')

To get the folder of a file just use:

os.path.dirname(path) 

To get a folder up just use os.path.dirname again

os.path.dirname(os.path.dirname(path))

You might want to check if __file__ is a symlink:

if os.path.islink(__file__): path = os.readlink (__file__)

From the current file path you could use:

os.path.join(os.path.dirname(__file__),'..','img','banner.png')