Используя 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?
hobbes3
источник
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вместо '..'.

forivall
источник
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__)
locojay
источник
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
18

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

BASE_DIR = os.path.join( os.path.dirname( __file__ ), '..' )
Алан Виарс
источник
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"

pythonHelpRequired
источник
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',
)
haterh
источник
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
Jo3l
источник
0

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

Шварма
источник
0

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

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

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

other_image_path = os.path.join(one_directory_up_path, 'other.jpg')
abdullahselek
источник