Usando os.path de Python, ¿cómo subo un directorio?

224

Recientemente actualicé Django de v1.3.1 a v1.4.

En mi viejo settings.py tengo

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

Esto apuntará a /Users/hobbes3/Sites/mysite/templates, pero porque Django v1.4 movió la carpeta del proyecto al mismo nivel que las carpetas de la aplicación , mi settings.pyarchivo ahora está en /Users/hobbes3/Sites/mysite/mysite/lugar de /Users/hobbes3/Sites/mysite/.

Entonces, en realidad mi pregunta ahora es doble:

  1. ¿Cómo uso os.pathpara mirar un directorio un nivel superior desde__file__ ? En otras palabras, quiero /Users/hobbes3/Sites/mysite/mysite/settings.pyencontrar /Users/hobbes3/Sites/mysite/templatesusando rutas relativas.
  2. Debería ser de mantenimiento de la templatecarpeta (que tiene plantillas cruzada de aplicaciones, como admin, registration, etc.) en el proyecto de /User/hobbes3/Sites/mysitenivel o en /User/hobbes3/Sites/mysite/mysite?
hobbes3
fuente
Cant que acaba de utilizar ospara cdque ../mysite? O cualquier comando que desee
prelic
@prelic Hmm? No entiendo. Estoy tratando de evitar codificar el camino, porque lo uso settings.pyen varios servidores. La única diferencia podría ser las credenciales de la base de datos. Estaba leyendo la os.pathdocumentación pero no pude encontrar un comando que te permitiera subir un directorio. Al igual cd ...
hobbes3
2
@ hobbes3 Puede os.path.join( os.path.dirname( __file__ ), '..' ) ..significar el directorio de arriba en todo el sistema de archivos, no solo cuando se pasa a cd.
Michael Berkowski
3
@Michael, probablemente sea mejor usaros.path.join( os.path.dirname ( __file__), os.path.pardir)
mgilson

Respuestas:

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

En cuanto a dónde debe ir la carpeta de plantillas, no lo sé desde que salió Django 1.4 y aún no lo he mirado. Probablemente debería hacer otra pregunta sobre SE para resolver ese problema.

También puede usar normpathpara limpiar el camino, en lugar de abspath. Sin embargo, en esta situación, Django espera una ruta absoluta en lugar de una ruta relativa.

Para compatibilidad multiplataforma, use en os.pardirlugar de '..'.

forivall
fuente
44
¿Es una mala idea usar ..o algo así? ¿Por qué esta respuesta obtiene menos votos?
hobbes3
1
No sé por qué recibe menos votos, pero es lo que siempre he usado. Incluso se define en el ejemplo para normpath. Además, atravesará los enlaces simbólicos correctamente.
Forivall
1
Usar abspath simplemente lo limpiará un poco. Si no está allí, la cadena real para el nombre de ruta será /Users/hobbes3/Sites/mysite/mysite/../templatesperfectamente perfecta, pero un poco más desordenada. También asegura que se obedezca el recordatorio de Django para usar rutas absolutas. Si se encuentra en una situación diferente que usa una ruta relativa, debe usar normpath para simplificar sus rutas.
Forivall
2
Esta pregunta se acaba de hacer con respecto a la migración de la estructura de carpetas para la nueva versión de Django , por lo que probablemente debería considerar eso para resolver su segundo problema.
forivall
1
@Zitrax ¿Conoces alguna plataforma en la que esto sea diferente, o solo está ahí para la seguridad futura? (Realmente no sabía os.pardir, nunca llegué al final de los osdocumentos)
forivall
98

Para obtener la carpeta de un archivo simplemente use:

os.path.dirname(path) 

Para obtener una carpeta, simplemente úsela os.path.dirnamenuevamente

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

Es posible que desee comprobar si __file__es un enlace simbólico:

if os.path.islink(__file__): path = os.readlink (__file__)
locojay
fuente
17
¿Hay alguna manera de subir ncarpetas sin tener que llamar a las os.path.dirname nhoras?
Oriol Nieto
99
@OriolNieto Sí, a partir de la versión Python 3.4+ puedes usar pathlib.Path.parents[levels_up-1]. Vea esta pregunta para obtener más soluciones
jwalton
23

Si está utilizando Python 3.4 o más reciente, una forma conveniente de subir varios directorios es 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
fuente
2
Este es definitivamente el método más limpio.
hobbes3
18

Quieres exactamente esto:

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

Personalmente, iría por el enfoque funcional

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

current_dirs_parent = get_parent_dir(os.getcwd())
Lord Sumner
fuente
Tenga cuidado, esta respuesta no funciona si la entrada contiene una barra inclinada final, por ejemplo, os.path.dirname('/tmp/lala/')aún devuelve'/tmp/lala'
Fruit
El caso de barra inclinada final puede referir esta respuesta: stackoverflow.com/a/25669963/1074998
Fruit
7

Creo que lo más fácil es reutilizar dirname () para que pueda llamar

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

si el archivo está en /Users/hobbes3/Sites/mysite/templates/method.py

Esto devolverá "/ Users / hobbes3 / Sites / mysite"

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

Actualizar:

Si sucede que "copia" a settings.pytravés del enlace simbólico, la respuesta de @ forivall es mejor:

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

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

El método anterior 'verá' wrong.htmlmientras que el método de @ forivall veráright.html

En ausencia de enlaces simbólicos, las dos respuestas son idénticas.

Antony Hatchkins
fuente
¿Hay algo malo con este enfoque? Funciona bien y se ve bien pero un poco hack;;
Gricha
Es ligeramente diferente de la respuesta aceptada en la forma en que trata los enlaces. Son idénticos de lo contrario.
Antony Hatchkins
6

Esto puede ser útil para otros casos en los que desea subir x carpetas. Solo corre walk_up_folder(path, 6)para subir 6 carpetas.

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
fuente
Podría usar en for _ in xrange(depth)lugar de hacer un seguimiento de la variable local.
Zitrax
2

Para un paranoico como yo, preferiría este

TEMPLATE_DIRS = (
    __file__.rsplit('/', 2)[0] + '/templates',
)
haterh
fuente
8
tal vez en lugar de '/'que debería usaros.sep
djhaskin987
1

Para subir ncarpetas ... ejecutaup(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
fuente
0

Por supuesto: simplemente usar os.chdir(..).

El shwarma
fuente
0

Con el uso os.pathpodemos subir un directorio así

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

También después de encontrar el directorio que desea, puede unirse con otra ruta de archivo / directorio

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