Usando o os.path do Python, como subo um diretório?

224

Recentemente, atualizei o Django da v1.3.1 para a v1.4.

Na minha idade settings.pyeu tenho

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

Isso apontará para /Users/hobbes3/Sites/mysite/templates, mas como o Django v1.4 moveu a pasta do projeto para o mesmo nível das pastas do aplicativo , meu settings.pyarquivo está agora em /Users/hobbes3/Sites/mysite/mysite/vez de /Users/hobbes3/Sites/mysite/.

Na verdade, minha pergunta agora é dupla:

  1. Como eu uso os.pathpara procurar um diretório um nível acima de __file__. Em outras palavras, eu quero /Users/hobbes3/Sites/mysite/mysite/settings.pyencontrar /Users/hobbes3/Sites/mysite/templatesusando caminhos relativos.
  2. Devo estar mantendo a templatepasta (que tem modelos de cross-aplicação, como admin, registration, etc.) para o projeto /User/hobbes3/Sites/mysitenível ou em /User/hobbes3/Sites/mysite/mysite?
hobbes3
fonte
Cant você acabou de usar ospara cda ../mysite? Ou qualquer comando que você quer
Prelic
@prelic Hmm? Eu não entendo Estou tentando evitar a codificação do caminho, porque uso o mesmo settings.pyem vários servidores. A única diferença pode ser as credenciais do banco de dados. Eu estava lendo a os.pathdocumentação, mas não consegui encontrar um comando que permita que você suba um diretório. Like cd ...
hobbes3
2
@ hobbes3 você pode simplesmente os.path.join( os.path.dirname( __file__ ), '..' ) ..significa o diretório acima todo o sistema de arquivos, não apenas quando passou para cd.
Michael Berkowski 24/03
3
@ Michael, provavelmente é melhor usaros.path.join( os.path.dirname ( __file__), os.path.pardir)
mgilson

Respostas:

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

Quanto aonde a pasta de templates deve ir, eu não sei desde que o Django 1.4 acabou de sair e ainda não a examinei. Você provavelmente deve fazer outra pergunta no SE para resolver esse problema.

Você também pode usar normpathpara limpar o caminho, em vez de abspath. No entanto, nesta situação, o Django espera um caminho absoluto, e não um caminho relativo.

Para compatibilidade entre plataformas, use em os.pardirvez de '..'.

forivall
fonte
4
É uma má idéia usar ..ou algo assim? Por que esta resposta está recebendo menos votos?
hobbes3
1
Não sei por que está recebendo menos votos, mas é o que sempre usei. É mesmo definido no exemplo para normpath. Além disso, ele percorrerá links simbólicos corretamente.
forivall
1
Usar o abspath apenas o limpará um pouco. Se não estiver lá, a string real para o nome do caminho será /Users/hobbes3/Sites/mysite/mysite/../templates, o que é perfeitamente correto, mas um pouco mais confuso. Ele também garante que o lembrete do Django para usar caminhos absolutos seja obedecido. Se você estiver em uma situação diferente que usa um caminho relativo, use normpath para simplificar seus caminhos.
Forivall
2
Esta pergunta foi feita apenas sobre a migração da estrutura de pastas para a nova versão do Django , então você provavelmente deve procurar por isso para resolver seu segundo problema.
Forivall
1
@Zitrax Você conhece alguma plataforma em que isso seria diferente ou existe apenas para segurança futura? (Na verdade, eu não sabia os.pardir, nunca cheguei ao fundo dos osdocumentos)
forivall
98

Para obter a pasta de um arquivo, basta usar:

os.path.dirname(path) 

Para abrir uma pasta, basta usar os.path.dirnamenovamente

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

Convém verificar se __file__é um link simbólico:

if os.path.islink(__file__): path = os.readlink (__file__)
locojay
fonte
17
Existe uma maneira de subir as npastas sem ter que ligar para o os.path.dirname nhorário?
Oriol Nieto
9
@OriolNieto Sim, a partir da versão Python 3.4+ você pode usar pathlib.Path.parents[levels_up-1]. Veja esta pergunta para obter mais soluções
jwalton 04/04/19
23

Se você estiver usando o Python 3.4 ou mais recente, uma maneira conveniente de mover vários diretórios é 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
fonte
2
Este é definitivamente o método mais limpo.
hobbes3
18

Você quer exatamente isso:

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

Pessoalmente, eu iria para a abordagem de função

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

current_dirs_parent = get_parent_dir(os.getcwd())
Lord Sumner
fonte
Tenha cuidado esta resposta não funciona se a entrada contém barra invertida, por exemplo, os.path.dirname('/tmp/lala/')ainda retornar'/tmp/lala'
Fruit
O caso da barra final pode consultar esta resposta: stackoverflow.com/a/25669963/1074998
Fruit
7

Acho que a coisa mais fácil é reutilizar o dirname () para que você possa ligar

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

se o seu arquivo estiver em /Users/hobbes3/Sites/mysite/templates/method.py

Isso retornará "/ Usuários / hobbes3 / Sites / meu site"

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

Atualizar:

Se você "copiar" settings.pypor meio de ligação simbólica, a resposta do @ forivall é melhor:

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

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

O método acima 'verá' wrong.htmlenquanto o método do @ forivall veráright.html

Na ausência de links simbólicos, as duas respostas são idênticas.

Antony Hatchkins
fonte
Há algo de errado com essa abordagem? Ele funciona agradável e aparência agradável, mas um pouco hackish;)
Gricha
É um pouco diferente da resposta aceita na forma como lida com os links. Eles são idênticos caso contrário.
Antony Hatchkins
6

Isso pode ser útil para outros casos em que você deseja subir x pastas. Basta correr walk_up_folder(path, 6)para subir 6 pastas.

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
fonte
Poderia apenas usar em for _ in xrange(depth)vez de acompanhar a variável local.
Zitrax
2

Para um paranóico como eu, eu preferiria este

TEMPLATE_DIRS = (
    __file__.rsplit('/', 2)[0] + '/templates',
)
haterh
fonte
8
Talvez em vez de '/'você deve usaros.sep
djhaskin987
1

Para subir as npastas ... executeup(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
fonte
0

Claro: basta usar os.chdir(..).

The Shwarma
fonte
0

Com o uso os.path, podemos subir um diretório assim

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

depois de encontrar o diretório que você deseja, você pode ingressar em outro caminho de arquivo / diretório

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