Jak przejść do jednego katalogu za pomocą os.path Pythona?

224

Niedawno zaktualizowałem Django z wersji 1.3.1 do wersji 1.4.

W moim starym settings.pymam

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

To wskaże /Users/hobbes3/Sites/mysite/templates, ale ponieważ Django v1.4 przeniósł folder projektu na ten sam poziom, co foldery aplikacji , mój settings.pyplik jest teraz /Users/hobbes3/Sites/mysite/mysite/zamiast /Users/hobbes3/Sites/mysite/.

Tak więc moje pytanie jest teraz dwojakie:

  1. Jak użyć, os.pathaby spojrzeć na katalog o jeden poziom wyżej od __file__. Innymi słowy, chcę /Users/hobbes3/Sites/mysite/mysite/settings.pyznaleźć /Users/hobbes3/Sites/mysite/templatesprzy użyciu ścieżek względnych.
  2. Powinienem być utrzymanie templatefolder (który ma przekrój szablony aplikacji, jak admin, registrationetc.), w projekcie /User/hobbes3/Sites/mysitepoziomu lub co /User/hobbes3/Sites/mysite/mysite?
hobbes3
źródło
Nie można po prostu użyć osdo cdcelu ../mysite? Lub cokolwiek chcesz
prelic
@prelic Hmm? Nie rozumiem. Staram się unikać twardego wpisywania ścieżki, ponieważ używam tego samego settings.pyna wielu serwerach. Jedyną różnicą mogą być poświadczenia bazy danych. Czytałem os.pathdokumentację, ale nie mogłem znaleźć polecenia, które pozwoli ci przejść do jednego katalogu. Jak cd ...
hobbes3
2
@ hobbes3 Możesz po prostu os.path.join( os.path.dirname( __file__ ), '..' ) ..oznaczać powyższy katalog w całym systemie plików, nie tylko po przekazaniu do cd.
Michael Berkowski
3
@Michael, prawdopodobnie lepiej jest użyćos.path.join( os.path.dirname ( __file__), os.path.pardir)
mgilson

Odpowiedzi:

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

Jeśli chodzi o to, gdzie powinien iść folder szablonów, nie wiem, ponieważ Django 1.4 właśnie wyszedł i jeszcze go nie przeglądałem. Prawdopodobnie powinieneś zadać kolejne pytanie w sprawie SE, aby rozwiązać ten problem.

Możesz także użyć normpathdo czyszczenia ścieżki zamiast abspath. Jednak w tej sytuacji Django oczekuje ścieżki bezwzględnej, a nie ścieżki względnej.

Aby uzyskać zgodność między platformami, użyj os.pardirzamiast '..'.

forivall
źródło
4
Czy to zły pomysł, ..czy użyć czegoś takiego? Dlaczego ta odpowiedź ma mniej głosów?
hobbes3
1
Nie wiem, dlaczego dostaje mniej głosów, ale zawsze tego używałem. Jest nawet zdefiniowane w przykładzie dla normpath. Ponadto prawidłowo przejdzie dowiązania symboliczne.
forivall
1
Użycie abspath tylko trochę go oczyści. Jeśli go nie ma, rzeczywisty ciąg nazwy ścieżki będzie /Users/hobbes3/Sites/mysite/mysite/../templates, co jest w porządku, ale tylko trochę bardziej zagracony. Zapewnia również przestrzeganie przypomnienia Django o użyciu ścieżek bezwzględnych. Jeśli znajdujesz się w innej sytuacji, która korzysta ze ścieżki względnej, powinieneś użyć normpath, aby uprościć ścieżki.
forivall
2
To pytanie zostało właśnie zadane w związku z migracją struktury folderów w nowej wersji Django , więc prawdopodobnie powinieneś spróbować rozwiązać drugi problem.
forivall
1
@Zitrax Czy znasz jakieś platformy, na których byłoby inaczej, czy jest to tylko dla bezpieczeństwa w przyszłości? (Tak naprawdę nie wiedziałem o tym os.pardir, nigdy tak naprawdę nie dotarłem do sedna osdokumentów)
forivall
98

Aby uzyskać folder pliku, użyj:

os.path.dirname(path) 

Aby otworzyć folder, użyj go os.path.dirnameponownie

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

Możesz sprawdzić, czy __file__jest to dowiązanie symboliczne:

if os.path.islink(__file__): path = os.readlink (__file__)
locojay
źródło
17
Czy istnieje sposób, aby przejść do nfolderów bez konieczności dzwonienia os.path.dirname n?
Oriol Nieto,
9
@OriolNieto Tak, od wersji Python 3.4+ można używać pathlib.Path.parents[levels_up-1]. Zobacz to pytanie dla bardziej rozwiązań
jwalton
23

Jeśli używasz języka Python 3.4 lub nowszego, wygodnym sposobem na przejście do wielu katalogów jest 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])  # "."
Birnbaum
źródło
2
To zdecydowanie najczystsza metoda.
hobbes3
18

Chcesz dokładnie to:

BASE_DIR = os.path.join( os.path.dirname( __file__ ), '..' )
Alan Viars
źródło
9

Osobiście wybrałbym podejście funkcyjne

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

current_dirs_parent = get_parent_dir(os.getcwd())
Lord Sumner
źródło
Uważaj, ta odpowiedź nie działa, jeśli dane wejściowe zawierają końcowe ukośniki, np. os.path.dirname('/tmp/lala/')Wciąż zwracają'/tmp/lala'
Fruit
Końcowy ukośnik może odnieść tę odpowiedź: stackoverflow.com/a/25669963/1074998
Fruit
7

Myślę, że najłatwiej jest po prostu ponownie użyć dirname (), abyś mógł zadzwonić

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

jeśli plik znajduje się w /Users/hobbes3/Sites/mysite/templates/method.py

Zwróci „/ Users / hobbes3 / Sites / mysite”

pythonHelpRequired
źródło
6
from os.path import dirname, realpath, join
join(dirname(realpath(dirname(__file__))), 'templates')

Aktualizacja:

Jeśli zdarzy ci się „kopiować” settings.pyprzez dowiązanie symboliczne, odpowiedź @ forivall jest lepsza:

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

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

Powyższa metoda „zobaczy”, wrong.htmlpodczas gdy metoda @ forivall zobaczyright.html

W przypadku braku dowiązań symbolicznych dwie odpowiedzi są identyczne.

Antony Hatchkins
źródło
Czy jest coś nie tak z tym podejściem? Działa ładnie i ładnie, ale trochę hackish;)
Gricha
Różni się nieco od przyjętej odpowiedzi w tym, jak radzi sobie z linkami. W przeciwnym razie są identyczne.
Antony Hatchkins
6

Może to być przydatne w innych przypadkach, gdy chcesz podnieść x folderów w górę. Wystarczy uruchomić, walk_up_folder(path, 6)aby przejść o 6 folderów.

def walk_up_folder(path, depth=1):
    _cur_depth = 1        
    while _cur_depth < depth:
        path = os.path.dirname(path)
        _cur_depth += 1
    return path   
Marcus Krautwurst
źródło
Można po prostu użyć for _ in xrange(depth)zamiast śledzić zmienną lokalną.
Zitrax
2

Dla takiego paranoika jak ja wolałbym ten

TEMPLATE_DIRS = (
    __file__.rsplit('/', 2)[0] + '/templates',
)
Haterh
źródło
8
może zamiast tego '/'powinieneś użyćos.sep
djhaskin987 30.01.15
1

Aby przejść do nfolderów ... uruchomup(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
źródło
0

Oczywiście: po prostu użyj os.chdir(..).

Shwarma
źródło
0

Za pomocą os.pathmożemy przejść o jeden katalog wyżej

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

także po znalezieniu żądanego katalogu możesz dołączyć do innej ścieżki do pliku / katalogu

other_image_path = os.path.join(one_directory_up_path, 'other.jpg')
abdullahselek
źródło