En utilisant os.path de Python, comment remonter un répertoire?

224

J'ai récemment mis à niveau Django de la v1.3.1 vers la v1.4.

Dans mon ancien settings.pyj'ai

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

Cela indiquera /Users/hobbes3/Sites/mysite/templates, mais parce que Django v1.4 a déplacé le dossier du projet au même niveau que les dossiers d'application , mon settings.pyfichier est maintenant à la /Users/hobbes3/Sites/mysite/mysite/place de /Users/hobbes3/Sites/mysite/.

Donc en fait ma question est maintenant double:

  1. Comment puis-je utiliser os.pathpour regarder un répertoire un niveau au-dessus de __file__. En d'autres termes, je veux /Users/hobbes3/Sites/mysite/mysite/settings.pytrouver en /Users/hobbes3/Sites/mysite/templatesutilisant des chemins relatifs.
  2. Dois - je garderai le templatedossier (qui a des modèles cross-app, comme admin, registration, etc.) au projet /User/hobbes3/Sites/mysiteniveau ou à /User/hobbes3/Sites/mysite/mysite?
hobbes3
la source
Cant que vous venez d' utiliser ospour cdde ../mysite? Ou quelle que soit la commande que vous voulez
prélic
@prelic Hmm? Je ne comprends pas. J'essaie d'éviter de coder en dur le chemin, car j'utilise le même settings.pysur plusieurs serveurs. La seule différence pourrait être les informations d'identification de la base de données. Je lisais la os.pathdocumentation mais je n'ai pas trouvé de commande qui vous permette de remonter dans un répertoire. Comme cd ...
hobbes3
2
@ hobbes3 Vous pouvez juste os.path.join( os.path.dirname( __file__ ), '..' ) ..signifie le répertoire ci - dessus à travers le système de fichiers, pas seulement lorsqu'il est passé à cd.
Michael Berkowski
3
@Michael, il est probablement préférable d'utiliseros.path.join( os.path.dirname ( __file__), os.path.pardir)
mgilson

Réponses:

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

En ce qui concerne le dossier des modèles, je ne sais pas depuis que Django 1.4 vient de sortir et je ne l'ai pas encore regardé. Vous devriez probablement poser une autre question sur SE pour résoudre ce problème.

Vous pouvez également utiliser normpathpour nettoyer le chemin plutôt que abspath. Cependant, dans cette situation, Django attend un chemin absolu plutôt qu'un chemin relatif.

Pour la compatibilité multiplateforme, utilisez os.pardirplutôt que '..'.

forivall
la source
4
Est-ce une mauvaise idée à utiliser ..ou quelque chose? Pourquoi cette réponse obtient-elle moins de votes?
hobbes3
1
Je ne sais pas pourquoi il obtient moins de votes, mais c'est ce que j'ai toujours utilisé. Il est même défini dans l'exemple de normpath. De plus, il traversera correctement les liens symboliques.
forivall
1
Utiliser abspath va juste le nettoyer un peu. Si ce n'est pas le cas, la chaîne réelle pour le nom du chemin sera /Users/hobbes3/Sites/mysite/mysite/../templates, ce qui est parfaitement bien, mais juste un peu plus encombré. Il garantit également que le rappel de Django d'utiliser des chemins absolus est respecté. Si vous êtes dans une situation différente qui utilise un chemin relatif, vous devez plutôt utiliser normpath pour simplifier vos chemins.
forivall
2
Cette question vient d'être posée concernant la migration de la structure des dossiers pour la nouvelle version de Django , vous devriez donc probablement vous en occuper pour résoudre votre deuxième problème.
forivall
1
@Zitrax Connaissez-vous des plates-formes où cela serait différent, ou est-ce juste pour la sécurité future? (Je ne savais pas vraiment, je ne suis os.pardirjamais os
allé
98

Pour obtenir le dossier d'un fichier, utilisez simplement:

os.path.dirname(path) 

Pour ouvrir un dossier, utilisez-le à os.path.dirnamenouveau

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

Vous voudrez peut-être vérifier s'il __file__s'agit d'un lien symbolique:

if os.path.islink(__file__): path = os.readlink (__file__)
locojay
la source
17
Existe-t-il un moyen de remonter les ndossiers sans avoir à appeler les os.path.dirname nheures?
Oriol Nieto
9
@OriolNieto Oui, à partir de la version Python 3.4+, vous pouvez utiliser pathlib.Path.parents[levels_up-1]. Voir cette question pour plus de solutions
jwalton
23

Si vous utilisez Python 3.4 ou une version plus récente, un moyen pratique de remonter plusieurs répertoires est le suivant 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
la source
2
C'est certainement la méthode la plus propre.
hobbes3
18

Vous voulez exactement ceci:

BASE_DIR = os.path.join( os.path.dirname( __file__ ), '..' )
Alan Viars
la source
9

Personnellement, j'opterais pour l'approche fonctionnelle

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

current_dirs_parent = get_parent_dir(os.getcwd())
Lord Sumner
la source
Attention, cette réponse ne fonctionne pas si l'entrée contient une barre oblique, par exemple os.path.dirname('/tmp/lala/')toujours retour'/tmp/lala'
Fruit
Le cas de barre oblique de fin peut renvoyer cette réponse: stackoverflow.com/a/25669963/1074998
Fruit
7

Je pense que la chose la plus simple à faire est simplement de réutiliser dirname () afin que vous puissiez appeler

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

si votre fichier se trouve dans /Users/hobbes3/Sites/mysite/templates/method.py

Cela renverra "/ Users / hobbes3 / Sites / mysite"

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

Mettre à jour:

S'il vous arrive de "copier" settings.pyvia la liaison symbolique, la réponse de @ forivall est meilleure:

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

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

La méthode ci-dessus 'verra' wrong.htmltandis que la méthode de @ forivall verraright.html

En l'absence de liens symboliques, les deux réponses sont identiques.

Antony Hatchkins
la source
Y a-t-il un problème avec cette approche? Cela fonctionne bien et a l'air sympa mais un peu hackish;)
Gricha
Elle est légèrement différente de la réponse acceptée dans la façon dont elle traite les liens. Ils sont identiques sinon.
Antony Hatchkins
6

Cela peut être utile dans d'autres cas où vous souhaitez remonter x dossiers. Il suffit de courir walk_up_folder(path, 6)pour monter 6 dossiers.

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
la source
Pourrait simplement utiliser for _ in xrange(depth)au lieu de garder une trace de la variable locale.
Zitrax
2

Pour un paranoïaque comme moi, je préfère celui-ci

TEMPLATE_DIRS = (
    __file__.rsplit('/', 2)[0] + '/templates',
)
haterh
la source
8
peut-être au lieu de '/'vous devriez utiliseros.sep
djhaskin987
1

Pour remonter les ndossiers ... exécutezup(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
la source
0

Bien sûr: utilisez simplement os.chdir(..).

Le Shwarma
la source
0

Avec l'aide, os.pathnous pouvons monter un répertoire comme ça

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

également après avoir trouvé le répertoire que vous voulez, vous pouvez vous joindre à un autre chemin de fichier / répertoire

other_image_path = os.path.join(one_directory_up_path, 'other.jpg')
abdullahselek
la source