ใช้ os.path ของ Python ฉันจะขึ้นหนึ่งไดเรกทอรีได้อย่างไร


224

ฉันเพิ่งอัพเกรด Django จาก v1.3.1 เป็น v1.4

ในวัยชราsettings.pyฉันมี

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

นี้จะชี้ไป/Users/hobbes3/Sites/mysite/templatesแต่เพราะ Django v1.4 ย้ายโฟลเดอร์โครงการให้อยู่ในระดับเดียวกับโฟลเดอร์แอปของฉันsettings.pyไฟล์ขณะนี้อยู่ในแทน/Users/hobbes3/Sites/mysite/mysite//Users/hobbes3/Sites/mysite/

ดังนั้นคำถามของฉันตอนนี้สองเท่า:

  1. ฉันจะใช้os.pathเพื่อดูไดเรกทอรีหนึ่งระดับด้านบน__file__ได้อย่างไร กล่าวอีกนัยหนึ่งฉันต้องการ/Users/hobbes3/Sites/mysite/mysite/settings.pyค้นหา/Users/hobbes3/Sites/mysite/templatesโดยใช้เส้นทางสัมพัทธ์
  2. ฉันควรจะรักษาtemplateโฟลเดอร์ (ซึ่งมีแม่แบบข้ามแอปเช่นadmin, registrationฯลฯ ) ในโครงการ/User/hobbes3/Sites/mysiteระดับหรือ/User/hobbes3/Sites/mysite/mysite?

คุณไม่เพียงแค่ใช้osไปcdเพื่อ../mysite? หรือคำสั่งใดก็ตามที่คุณต้องการ
รีลิค

@prelic อืม ฉันไม่เข้าใจ ฉันพยายามหลีกเลี่ยงการเข้ารหัสฮาร์ดไดรฟ์เนื่องจากฉันใช้สิ่งเดียวกันsettings.pyในเซิร์ฟเวอร์หลายเครื่อง ความแตกต่างเพียงอย่างเดียวอาจเป็นข้อมูลรับรองฐานข้อมูล ฉันอ่านos.pathเอกสารแต่ฉันไม่พบคำสั่งที่ให้คุณขึ้นหนึ่งไดเรกทอรี กดcd ..ไลค์
hobbes3

2
@ hobbes3 คุณก็สามารถos.path.join( os.path.dirname( __file__ ), '..' ) ..หมายถึงไดเรกทอรีดังกล่าวข้างต้นตลอดทั้งระบบแฟ้มไม่เพียง cdแต่เมื่อผ่านไป
Michael Berkowski

3
@Michael มันอาจจะดีกว่าคือการใช้งานos.path.join( os.path.dirname ( __file__), os.path.pardir)
mgilson

คำตอบ:


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

เท่าที่ควรจะไปที่โฟลเดอร์เทมเพลตฉันไม่รู้ตั้งแต่ Django 1.4 เพิ่งออกมาและฉันยังไม่ได้ดูเลย คุณควรถามคำถามอื่นใน SE เพื่อแก้ไขปัญหานั้น

นอกจากนี้คุณยังสามารถใช้ในการทำความสะอาดเส้นทางมากกว่าnormpath abspathอย่างไรก็ตามในสถานการณ์นี้ Django คาดหวังเส้นทางที่แน่นอนมากกว่าเส้นทางที่เกี่ยวข้อง

สำหรับการทำงานร่วมกันข้ามแพลตฟอร์มใช้แทนos.pardir'..'


4
มันเป็นความคิดที่ดีที่จะใช้..หรืออะไร? ทำไมคำตอบนี้ถึงได้รับการโหวตน้อยลง?
hobbes3

1
ฉันไม่รู้ว่าทำไมมันถึงได้รับคะแนนน้อยลง แต่มันเป็นสิ่งที่ฉันใช้มาตลอด normpathมันกำหนดแม้ในตัวอย่างสำหรับ นอกจากนี้มันจะสำรวจ symlink อย่างถูกต้อง
forivall

1
การใช้ abspath จะทำให้มันสะอาดขึ้นเล็กน้อย หากไม่มีอยู่สตริงที่แท้จริงของชื่อพา ธ จะเป็นอะไร/Users/hobbes3/Sites/mysite/mysite/../templatesที่สมบูรณ์แบบ แต่ก็มีความยุ่งเหยิงเพิ่มขึ้นอีกเล็กน้อย นอกจากนี้ยังทำให้มั่นใจได้ว่าการเตือนของ Django ในการใช้เส้นทางที่สมบูรณ์นั้นเป็นไปตาม หากคุณอยู่ในสถานการณ์อื่นที่ใช้เส้นทางสัมพัทธ์คุณควรใช้ normpath เพื่อทำให้เส้นทางของคุณง่ายขึ้นแทน
forivall

2
คำถามนี้ถูกถามเพียงเกี่ยวกับการย้ายโครงสร้างโฟลเดอร์สำหรับ Django เวอร์ชันใหม่ดังนั้นคุณอาจจะต้องดูที่การแก้ไขปัญหาที่สองของคุณ
forivall

1
@Zitrax คุณรู้หรือไม่ว่ามีแพลตฟอร์มใดบ้างที่สิ่งนี้แตกต่างกันหรือมีเพียงเพื่อความปลอดภัยในอนาคตหรือไม่ (ฉันไม่รู้จริงos.pardirไม่เคยไปที่ด้านล่างของosเอกสาร)
forivall

98

ในการรับโฟลเดอร์ของไฟล์ให้ใช้:

os.path.dirname(path) 

ในการทำให้โฟลเดอร์ใช้งานได้os.path.dirnameอีกครั้ง

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

คุณอาจต้องการตรวจสอบว่า__file__เป็น symlink:

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

17
มีวิธีการเพิ่มnโฟลเดอร์โดยไม่ต้องโทรos.path.dirname nครั้งหรือไม่?
Oriol Nieto

9
@OriolNieto ใช่แล้วตั้งแต่เวอร์ชัน Python 3.4+ คุณสามารถpathlib.Path.parents[levels_up-1]ใช้ได้ ดูคำถามนี้สำหรับวิธีแก้ปัญหาเพิ่มเติม
35432

23

หากคุณใช้ Python 3.4 หรือใหม่กว่าวิธีที่สะดวกในการเลื่อนขึ้นหลาย ๆ ไดเรกทอรีคือ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
นี่เป็นวิธีที่สะอาดที่สุดแน่นอน
hobbes3


9

โดยส่วนตัวฉันจะไปหาฟังก์ชั่น

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

current_dirs_parent = get_parent_dir(os.getcwd())

ระวังคำตอบนี้ใช้ไม่ได้ถ้าอินพุตมีเครื่องหมายสแลชต่อท้ายเช่นos.path.dirname('/tmp/lala/')ยังคงกลับมา'/tmp/lala'
Fruit

เคสสแลชต่อท้ายสามารถอ้างถึงคำตอบนี้: stackoverflow.com/a/25669963/1074998
Fruit

7

ฉันคิดว่าสิ่งที่ง่ายที่สุดที่ต้องทำคือเพียงใช้ dirname () ซ้ำอีกครั้งดังนั้นคุณสามารถโทรหา

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

หากไฟล์ของคุณอยู่ที่ /Users/hobbes3/Sites/mysite/templates/method.py

สิ่งนี้จะส่งคืน "/ Users / hobbes3 / Sites / mysite"


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

ปรับปรุง:

หากคุณ "คัดลอก" settings.pyผ่านการเชื่อมโยง symlinking คำตอบของ @ forivall จะดีกว่า:

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

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

วิธีการข้างต้นจะ 'เห็น' wrong.htmlในขณะที่วิธีการ @ forivall จะเห็นright.html

ในการขาด symlink ทั้งสองคำตอบเหมือนกัน


มีอะไรผิดปกติกับวิธีนี้หรือไม่? มันทำงานได้ดีและดูดี แต่ hackish เล็ก ๆ น้อย ๆ ;)
Gricha

มันแตกต่างจากคำตอบที่ยอมรับเล็กน้อยในวิธีการจัดการกับลิงค์ พวกเขาเหมือนกันเป็นอย่างอื่น
Antony Hatchkins

6

สิ่งนี้อาจมีประโยชน์สำหรับกรณีอื่น ๆ ที่คุณต้องการเพิ่มโฟลเดอร์ x เพียงแค่วิ่งwalk_up_folder(path, 6)ขึ้นไป 6 โฟลเดอร์

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

สามารถใช้for _ in xrange(depth)แทนการติดตามตัวแปรโลคัล
Zitrax

2

สำหรับคนหวาดระแวงอย่างฉันฉันชอบอันนี้

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

8
บางที'/'คุณควรใช้แทนos.sep
djhaskin987

1

เพื่อไปที่nโฟลเดอร์ up ... runup(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

ด้วยการใช้os.pathเราสามารถไปหนึ่งไดเรกทอรีขึ้นเช่นนั้น

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

หลังจากค้นหาไดเรกทอรีที่คุณต้องการแล้วคุณสามารถเข้าร่วมกับเส้นทางของไฟล์ / ไดเรกทอรีอื่น ๆ

other_image_path = os.path.join(one_directory_up_path, 'other.jpg')
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.