Використовуючи os.path Python, як мені підняти одну директорію?


224

Я нещодавно оновив Django з версії 1.3 до версії 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 Hmm? Я не розумію. Я намагаюся уникати жорсткого кодування шляху, тому що я використовую те саме settings.pyна декількох серверах. Єдиною різницею можуть бути облікові дані бази даних. Я читав os.pathдокументацію, але не зміг знайти команду, яка дозволить вам піднятися на один каталог. Як cd ...
hobbes3

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

3
@Michael, мабуть, краще використовуватиos.path.join( os.path.dirname ( __file__), os.path.pardir)
mgilson

Відповіді:


285
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, що ідеально добре, але просто трохи більше захаращено. Це також забезпечує дотримання нагадування Джанго про використання абсолютних шляхів. Якщо ви перебуваєте в іншій ситуації, яка використовує відносний шлях, вам слід скористатися нормпатом, щоб спростити свої шляхи.
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

Це повернеться "/ Користувачі / hobbes3 / Сайти / 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)замість відстеження локальної змінної.
Zitrax

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.