Usando os.path di Python, come posso salire di una directory?


224

Di recente ho aggiornato Django dalla v1.3.1 alla v1.4.

Nel mio vecchio l' settings.pyho fatto

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

Questo indicherà /Users/hobbes3/Sites/mysite/templates, ma poiché Django v1.4 ha spostato la cartella del progetto allo stesso livello delle cartelle dell'app , il mio settings.pyfile è ora al /Users/hobbes3/Sites/mysite/mysite/posto di /Users/hobbes3/Sites/mysite/.

Quindi in realtà la mia domanda ora è duplice:

  1. Come posso usare os.pathper guardare una directory sopra un livello __file__. In altre parole, voglio /Users/hobbes3/Sites/mysite/mysite/settings.pytrovare /Users/hobbes3/Sites/mysite/templatesusando percorsi relativi.
  2. Dovrei essere mantenendo la templatecartella (che dispone di modelli cross-app, come admin, registratione così via) al progetto di /User/hobbes3/Sites/mysitepiano o /User/hobbes3/Sites/mysite/mysite?

Non puoi abituarti osa cdfarlo ../mysite? O qualunque comando tu voglia
prelic

@prelic Hmm? Non capisco. Sto cercando di evitare l'hardcoding del percorso, perché utilizzo lo stesso settings.pyin più server. L'unica differenza potrebbe essere le credenziali del database. Stavo leggendo la os.pathdocumentazione ma non sono riuscito a trovare un comando che ti permetta di salire di una directory. Come cd ...
hobbes3,

2
@ hobbes3 Puoi semplicemente os.path.join( os.path.dirname( __file__ ), '..' ) ..indicare la directory sopra in tutto il filesystem, non solo quando passerai a cd.
Michael Berkowski,

3
@Michael, probabilmente è meglio usareos.path.join( os.path.dirname ( __file__), os.path.pardir)
mgilson

Risposte:


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

Per quanto riguarda dove dovrebbe andare la cartella dei modelli, non lo so da quando Django 1.4 è appena uscito e non l'ho ancora visto. Probabilmente dovresti porre un'altra domanda su SE per risolvere quel problema.

Puoi anche usare normpathper ripulire il percorso, piuttosto che abspath. Tuttavia, in questa situazione, Django si aspetta un percorso assoluto piuttosto che un percorso relativo.

Per la compatibilità multipiattaforma, utilizzare os.pardirinvece di '..'.


4
È una cattiva idea da usare ..o qualcosa del genere? Perché questa risposta ottiene meno voti?
hobbes3

1
Non so perché ottenga meno voti, ma è quello che ho sempre usato. È persino definito nell'esempio di normpath. Inoltre, attraverserà correttamente i collegamenti simbolici.
forivall

1
L'uso di abspath lo pulirà un po '. Se non è lì, la stringa effettiva per il nome del percorso sarà /Users/hobbes3/Sites/mysite/mysite/../templates, il che è perfettamente bene, ma solo un po 'più ingombra. Assicura inoltre che il promemoria di Django all'utilizzo di percorsi assoluti sia rispettato. Se ti trovi in ​​una situazione diversa che utilizza un percorso relativo, devi invece utilizzare normpath per semplificare i percorsi.
forivall


1
@Zitrax Conosci delle piattaforme in cui questo sarebbe diverso o è lì solo per la sicurezza futura? (In realtà non lo sapevo os.pardir, non sono mai arrivato in fondo alla osdocumentazione)
forivall

98

Per ottenere la cartella di un file basta usare:

os.path.dirname(path) 

Per ottenere una cartella, basta usare di os.path.dirnamenuovo

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

Potresti voler controllare se __file__è un link simbolico:

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

17
C'è un modo per andare su ncartelle senza dover chiamare i os.path.dirname ntempi?
Oriol Nieto,

9
@OriolNieto Sì, dalla versione Python 3.4+ è possibile utilizzare pathlib.Path.parents[levels_up-1]. Vedi questa domanda per ulteriori soluzioni
jwalton

23

Se si utilizza Python 3.4 o versioni successive, un modo conveniente per spostarsi su più directory è 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
Questo è sicuramente il metodo più pulito.
hobbes3,

18

Vuoi esattamente questo:

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

9

Personalmente, preferirei l'approccio funzionale

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

current_dirs_parent = get_parent_dir(os.getcwd())

Fai attenzione che questa risposta non funziona se l'input contiene una barra finale, ad esempio os.path.dirname('/tmp/lala/')ancora return'/tmp/lala'
Fruit

La barra rovesciata può fare riferimento a questa risposta: stackoverflow.com/a/25669963/1074998
Fruit

7

Penso che la cosa più semplice da fare sia solo riutilizzare dirname () in modo da poter chiamare

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

se il file è in /Users/hobbes3/Sites/mysite/templates/method.py

Questo restituirà "/ Users / hobbes3 / Sites / mysite"


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

Aggiornare:

Se ti capita di "copiare" settings.pytramite symlinking, la risposta di @ forivall è migliore:

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

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

Il metodo sopra "vedrà" wrong.htmlmentre vedrà il metodo di @ forivallright.html

In assenza di symlink le due risposte sono identiche.


C'è qualcosa di sbagliato in questo approccio? Funziona bene e sembra carino ma un po 'hacker;)
Gricha

È leggermente diverso dalla risposta accettata nel modo in cui gestisce i collegamenti. Sono identici altrimenti.
Antony Hatchkins,

6

Questo potrebbe essere utile per altri casi in cui vuoi andare su x cartelle. Esegui walk_up_folder(path, 6)per salire su 6 cartelle.

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

Potrebbe semplicemente usare for _ in xrange(depth)invece di tenere traccia della variabile locale.
Zitrax,

2

Per un paranoico come me, preferirei questo

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

8
forse al posto '/'tuo dovresti usareos.sep
djhaskin987 il

1

Per andare su ncartelle ... eseguireup(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

Con l'utilizzo os.pathpossiamo salire di una directory in questo modo

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

anche dopo aver trovato la directory che desideri puoi unirti ad altri percorsi di file / directory

other_image_path = os.path.join(one_directory_up_path, 'other.jpg')
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.