Используя Python os.path, как мне перейти в один каталог?

Недавно я обновил Django с версии 1.3.1 до версии 1.4.

В моем старом settings.py у меня есть

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.
)

Это укажет на /Users/hobbes3/Sites/mysite/templates, но поскольку Django v1.4 переместил папку проекта на тот же уровень, что и папки приложений, мой settings.py теперь находится в /Users/hobbes3/Sites/mysite/mysite/ вместо /Users/hobbes3/Sites/mysite/.

Итак, мой вопрос сейчас двоякий:

  • Как использовать os.path для просмотра каталога на одном уровне выше от __file__. Другими словами, я хочу, чтобы /Users/hobbes3/Sites/mysite/mysite/settings.py находил /Users/hobbes3/Sites/mysite/templates, используя относительные пути.
  • Должен ли я хранить папку template (у которой есть шаблоны кросс-приложений, такие как admin, registration и т.д.) на уровне проекта /User/hobbes3/Sites/mysite или в /User/hobbes3/Sites/mysite/mysite?

Ответ 1

os.path.abspath(os.path.join(os.path.dirname( __file__ ), '..', 'templates'))

Насколько папка шаблонов должна идти, я не знаю, так как Django 1.4 только что вышел, и я еще не посмотрел на него. Вероятно, вы должны задать другой вопрос в SE, чтобы решить эту проблему.

Вы также можете использовать normpath для очистки пути, а не abspath. Однако в этой ситуации Django ожидает абсолютный путь, а не относительный путь.

Для совместимости с кросс-платформой используйте os.pardir вместо '..'.

Ответ 2

Чтобы получить папку с файлом, просто используйте:

os.path.dirname(path) 

Чтобы получить папку, просто используйте os.path.dirname снова

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

Вы можете проверить, является ли __file__ символической ссылкой:

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

Ответ 3

Вы хотите именно это:

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

Ответ 4

Лично я бы пошел на функциональный подход

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

current_dirs_parent = get_parent_dir(os.getcwd())

Ответ 5

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

Update:

Если вам случится "копировать" settings.py через символическую привязку, лучше ответить на @forivall:

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

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

Метод выше будет "видеть" wrong.html, в то время как метод @forivall увидит right.html

В отсутствии символических ссылок два ответа идентичны.

Ответ 6

Если вы используете Python 3.4 или новее, удобный способ перемещения по нескольким каталогам - это 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])  # "."

Ответ 7

Я думаю, что проще всего просто повторить использование dirname() Поэтому вы можете позвонить

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

если файл находится в /Users/hobbes 3/Sites/mysite/templates/method.py

Это вернет "/Users/hobbes3/Sites/mysite"

Ответ 8

Это может быть полезно для других случаев, когда вы хотите перейти в x папки вверх. Просто запустите walk_up_folder(path, 6), чтобы перейти в 6 папок.

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

Ответ 9

Для параноика, как я, я бы предпочел этот

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

Ответ 10

Чтобы перейти на n папок вверх... запустить 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

Ответ 11

Конечно: просто используйте os.chdir(..).