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


224

Я недавно обновил 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/.

Так что на самом деле мой вопрос теперь имеет два аспекта:

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

Cant вы просто использовать osдля cdв ../mysite? Или любую команду, которую вы хотите
— prelic

@ прелишко Хмм? Я не понимаю Я пытаюсь избежать жесткого кодирования пути, потому что я использую его на settings.pyнескольких серверах. Единственной разницей могут быть учетные данные базы данных. Я читал os.pathдокументацию, но не смог найти команду, которая позволила бы вам перейти на один каталог. Как cd ...
— hobbes3

2
@ hobbes3 Вы можете просто os.path.join( os.path.dirname( __file__ ), '..' ) ..означает , что каталог выше по всей файловой системе, а не только при передаче cd.
— Майкл Берковски

3
@ Майкл, вероятно, лучше использоватьos.path.join( os.path.dirname ( __file__), os.path.pardir)
— mgilson

Ответы:


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

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

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

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


4
Это плохая идея ..или что-то в этом роде? Почему этот ответ получает меньше голосов?
— hobbes3

1
Я не знаю, почему он получает меньше голосов, но это то, что я всегда использовал. Это даже определено в примере для normpath. Кроме того, он будет правильно проходить символические ссылки.
— Forivall

1
Использование abspath просто немного его очистит. Если его там нет, будет указана фактическая строка для имени пути /Users/hobbes3/Sites/mysite/mysite/../templates, что вполне нормально, но немного более загромождено. Это также обеспечивает выполнение напоминания Django об использовании абсолютных путей. Если вы находитесь в другой ситуации, в которой используется относительный путь, вам следует использовать normpath для упрощения ваших путей.
— forivall

2
Этот вопрос был только что задан относительно миграции структуры папок для новой версии Django , поэтому вам, вероятно, следует обратиться к ней для решения вашей второй проблемы.
— forivall

1
@Zitrax Знаете ли вы о каких-либо платформах, где это будет отличаться, или это просто для будущей безопасности? (Я на самом деле не знал os.pardir, никогда не дошел до сути osдокументов)
— forivall

98

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

os.path.dirname(path) 

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

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

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

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

17
Есть ли способ идти вверх по nпапкам без необходимости звонить os.path.dirname nраз?
— Ориол Ньето

9
@OriolNieto Да, начиная с версии Python 3.4+, которую вы можете использовать pathlib.Path.parents[levels_up-1]. Посмотрите этот вопрос для получения дополнительных решений
— Jwalton

23

Если вы используете 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])  # "."

2
Это определенно самый чистый метод.
— hobbes3


9

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

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

current_dirs_parent = get_parent_dir(os.getcwd())

Будьте осторожны, этот ответ не работает, если вход содержит косую черту, например, по- os.path.dirname('/tmp/lala/')прежнему возвращается'/tmp/lala'
— Fruit

Конечный слеш может ссылаться на этот ответ: stackoverflow.com/a/25669963/1074998
— Fruit

7

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

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

если ваш файл находится по адресу /Users/hobbes3/Sites/mysite/templates/method.py

Это возвратит "/ Users / hobbes3 / Sites / mysite"


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

Обновить:

Если вам случится «копировать» с 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

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


Что-то не так с этим подходом? Это работает хорошо и выглядит красиво, но немного хакерски;)
— Gricha

Он немного отличается от принятого ответа тем, как он работает со ссылками. В противном случае они идентичны.
— Энтони Хэтчкинс

6

Это может быть полезно для других случаев, когда вы хотите перейти на 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   

Можно просто использовать for _ in xrange(depth)вместо отслеживания локальной переменной.
— Цитрак

2

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

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

8
возможно, вместо '/'вас следует использоватьos.sep
— djhaskin987

1

Чтобы перейти 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


0

С помощью os.pathмы можем перейти на один каталог вверх, как это

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

также после нахождения нужного вам каталога вы можете присоединиться с другим путем к файлу / каталогу

other_image_path = os.path.join(one_directory_up_path, 'other.jpg')
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.