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?

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


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

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])  # "."

2
Este é definitivamente o método mais limpo.
— hobbes3

18

Você quer exatamente isso:

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

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

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"


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.


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   

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',
)

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


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')
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.