جنگو فریمورک

راهنمای مسیردهی دایرکتوری‌ها در تنظیمات پروژه Django

مسیردهی یکی از مفاهیم پایه و اساسی در پروژه‌های django است که نقش مهمی در لود صحیح فایل‌های قالب، استاتیک و رسانه‌ای دارد. تعریف دقیق و صحیح مسیرها به کمک متغیر BASE_DIR باعث می‌شود پروژه قابلیت جابه‌جایی و پایداری در محیط‌های مختلف داشته باشد و از خطاهای رایج جلوگیری شود. درک درست این مفاهیم برای برنامه‌نویسان django واجب است تا بتوانند ساختار پروژه را بهینه و قابل مدیریت نگه دارند.

 

مفهوم پایه‌ی مسیردهی در پروژه‌های Django

در پروژه‌های Django، تعیین مسیر به این معناست که ما باید مشخص کنیم فایل‌های مختلف پروژه‌مان مثل فایل‌های تنظیمات، تمپلیت‌‌ها، فایل‌های استاتیک و یا مدیا در چه مسیری از پروژه قرار دارند. باید این مسیرها تعریف شده باشند تا جنگو بتواند آن‌ها را لود و استفاده کند.
برای این کار، معمولا از یک متغیر به نام BASE_DIR در فایل settings.py استفاده می‌شود. این متغیر مسیر اصلی یا روت پروژه را مشخص می‌کند، یعنی فولدری که در آن پروژه راه‌ اندازی شده است.
با کمک BASE_DIR می‌توانیم مسیر بقیه فایل‌ها را به صورت دقیق و قابل حمل مشخص کنیم، به‌طوری‌که حتی اگر پروژه را به یک کامپیوتر یا سرور دیگر منتقل کنیم، مسیرها همچنان درست کار کنند.
برای مثال:

 TEMPLATES = [
     {
         'DIRS': [BASE_DIR / "templates"],
         ...
     },
]

در واقع به django می‌گوییم قالب‌ها در فولدری به نام templates هستند که در روت اصلی پروژه قرار گرفته است.

به صورت خلاصه مسیردهی در django یعنی مشخص کردن دقیق محل فایل‌ها، به‌طوری که بتواند آن‌ها را پیدا کند و استفاده از BASE_DIR باعث می‌شود این کار راحت‌تر و بدون خطا انجام شده باشد.

 

BASE_DIR چیست و چرا مهم است؟

نمایی از روت اصلی پروژه جنگو

BASE_DIR یک متغیر در فایل settings.py پروژه Django است که روت اصلی پروژه را مشخص می‌کند. این متغیر معمولا با استفاده از پکیج pathlib تعریف می‌شود و به Django کمک می‌کند تا مسیر فایل‌های دیگر مانند قالب‌ها، فایل‌های استاتیک، مدیا را به‌صورت دقیق تعیین کند.

اهمیت‌های BASE_DIR:

  • نقطه شروع برای تمام مسیرها: تمام مسیرهای مهم در پروژه، مثل templates, static, media, و db.sqlite3 معمولا بر پایه‌ BASE_DIR تنظیم می‌شوند.

  • قابل حمل بودن پروژه: اگر مسیرها را به‌صورت hard-coded نوشته شود، پروژه ممکن است فقط بر روی یک سیستم خاص کار کند. اما با استفاده از BASE_DIR، پروژه بر روی هر سیستم یا سرور جدیدی بدون مشکل اجرا می‌شود.

  • مدیریت بهتر ساختار پروژه: با داشتن یک مرجع ثابت برای بیس مسیر، توسعه‌دهنده می‌تواند فولدرهای پروژه را به راحتی مدیریت کند.

مثال:

 from pathlib import Path  
BASE_DIR = Path(__file__).resolve().parent.parent 

در این مثال، عبارت (__file__) مسیر فایل settings.py است، و با .parent.parent دو سطح به بالا می‌رویم تا به فولدر اصلی پروژه برسیم (محلی که manage.py قرار دارد).

در نتیجه، BASE_DIR پایه‌ای‌ترین ابزار برای مدیریت مسیرها در تنظیمات جنگو است.

 

نحوه استفاده از os.path و Pathlib برای تعیین مسیرها

pathlib و  os.path

در پروژه‌های django، برای تعیین مسیر فایل‌ها یا دایرکتوری‌ها، معمولا از یکی از دو روش زیر استفاده می‌شود:

 

1. استفاده از os.path

کتابخانه‌ی os در پایتون، امکانات مختلفی برای کار با مسیرها فراهم می‌کند. در گذشته، این روش رایج‌تر بود.

 import os  
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 
TEMPLATES_DIR = os.path.join(BASE_DIR, 'templates') 
  • os.path.abspath(__file__): مسیر کامل فایل جاری را برمی‌گرداند.

  • ()os.path.dirname: یک مرحله به عقب در مسیر فایل می‌رود.

  • ()os.path.join: مسیرها را با هم ترکیب می‌کند.

 

2. استفاده از pathlib.Path (روش توصیه‌شده)

pathlib

کتابخانه pathlib در نسخه‌های جدیدتر پایتون معرفی شده و کار با مسیرها را ساده‌تر و خواناتر می‌کند.

 from pathlib import Path  
BASE_DIR = Path(__file__).resolve().parent.parent 
TEMPLATES_DIR = BASE_DIR / 'templates' 
  • ()Path(__file__).resolve مسیر کامل فایل را می‌دهد.

  • parent. به یک پوشه بالاتر اشاره می‌کند.

  • از / برای ترکیب مسیرها استفاده می‌شود (مانند join اما خواناتر).

 

کدام را استفاده کنیم؟

معیارها os.path pathlib
سادگی نوشتار معمولی خواناتر
نسخه پایتون همه نسخه‌ها python 3.4 به بالا
خوانایی کد کمتر بیشتر

 

در پروژه‌های جدید django بهتر است از pathlib استفاده شود مگر اینکه به دلیل سازگاری با نسخه‌های قدیمی پایتون، لازم باشد.

 

تنظیم مسیر فایل‌های استاتیک (Static Files) در Django

فولدرهای static و templates در جنگو

در django، فایل‌های استاتیک مثل css، js و تصاویر در زمان توسعه و اجرا از اهمیت زیادی برخوردارند. برای اینکه این فایل‌ها در زمان اجرا به‌درستی لود شوند، باید مسیر آن‌ها را در تنظیمات پروژه مشخص کنیم. در حالت توسعه (development)، django خودش مسئول سرو کردن فایل‌های استاتیک است، اما در حالت اجرا (production) باید آن‌ها را با ابزارهای جداگانه مثل nginx یا whitenoise مدیریت کرد. ما در این پست بر روی تنظیمات سمت پروژه تمرکز داریم.

ابتدا در فایل settings.py مسیرهای لازم را تعریف می‌کنیم. اگر ساختار پروژه به این صورت باشد:

myproject/
├── myapp/
│   └── static/
│       └── myapp/
├── staticfiles/
├── manage.py
└── myproject/
    └── settings.py

کدهای زیر را در settings.py وارد می‌کنیم:

import os
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

# static file addresses for development
STATIC_URL = '/static/'

# the location where collectstatic stores files (in production mode)
STATIC_ROOT = BASE_DIR / 'staticfiles'

# paths where Django looks for static files
STATICFILES_DIRS = [
    BASE_DIR / 'myapp' / 'static',
]

در حالت توسعه، وقتی فایل‌های استاتیک را در پوشه‌ای مثل myapp/static/myapp قرار می‌دهید، django آن‌ها را از آن مسیر با STATICFILES_DIRS پیدا می‌کند. اما در production، زمانی که دستور python manage.py collectstatic را اجرا می‌کنید، django همه فایل‌های استاتیک را از مسیرهای مشخص‌شده در STATICFILES_DIRS جمع‌آوری و در STATIC_ROOT ذخیره می‌کند.

برای اطمینان از سرو صحیح فایل‌ها در توسعه، مطمئن شوید که DEBUG = True و django.contrib.staticfiles در INSTALLED_APPS فعال است. در فایل urls.py اصلی نیز این کدها را برای حالت توسعه اضافه کنید:

from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    # urls
]

if settings.DEBUG:
    urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

با این تنظیمات، فایل‌های استاتیک شما در حالت توسعه به‌درستی نمایش داده می‌شوند و برای مرحله اجرا نیز آماده می‌شوند. تنظیم دقیق مسیرها به ساختار دایرکتوری پروژه بستگی دارد و برای هر پروژه می‌تواند سفارشی‌سازی شود.

 

 

مسیردهی به فایل‌های رسانه‌ای (Media Files)

فولدر media files در جنگو

فایل‌های رسانه‌ای شامل فایل‌هایی هستند که کاربران در طول استفاده از سایت آپلود می‌کنند، مثل تصویر پروفایل، ویدیو، یا فایل‌های پیوست. برای مدیریت این فایل‌ها باید مسیر ذخیره‌سازی آن‌ها را مشخص کرده و اطمینان حاصل کنیم که هم در زمان توسعه و هم در زمان اجرا، به درستی سرو می‌شوند. تفاوت فایل‌های media با static در این است که فایل‌های media توسط کاربران ایجاد میشوند اما فایل‌های static مربوط به ظاهر سایت هستند.

برای کانفیگ مسیر فایل‌های media، ابتدا تنظیمات زیر را به فایل settings.py پروژه اضافه می‌کنیم. فرض می‌کنیم فایل‌ها در پوشه‌ای به نام media/ در روت پروژه ذخیره خواهند شد:

import os
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

# URL prefix for media files
MEDIA_URL = '/media/'

# Absolute path where media files will be stored
MEDIA_ROOT = BASE_DIR / 'media'

سپس، برای اینکه django در حالت توسعه این فایل‌ها را نمایش دهد، باید در فایل urls.py پروژه، مسیرهایی برای سرو کردن آن‌ها اضافه کنیم. کد زیر را در urls.py اصلی پروژه قرار دهید:

from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    # your app routes here
]

if settings.DEBUG:
    # serve media files in development
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

با این تنظیمات، زمانی که کاربری فایلی را از طریق مدل یا فرم آپلود می‌کند، django آن را در مسیر مشخص‌شده در MEDIA_ROOT ذخیره می‌کند و در زمان توسعه از طریق MEDIA_URL در دسترس قرار میدهد. در production نیاز به پیکربندی مجزایی مثل استفاده از nginx یا یک سرویس ذخیره‌سازی خارجی مثل s3 وجود دارد، اما سیستم سمت django ثابت باقی می‌ماند.

 

مسیردهی به قالب‌ها (Templates) در Django

قالب‌ها فایل‌هایی هستند که ظاهر صفحات html را با استفاده از داده‌های دینامیک ایجاد می‌کنند. این فایل‌ها معمولا در پوشه‌ای به نام templates/ نگهداری می‌شوند و django از طریق تنظیمات مشخص‌شده آن‌ها را پیدا میکند. مسیردهی درست به قالب‌ها باعث می‌شود viewها بتوانند خروجی قابل نمایش تولید کنند. این تنظیمات برای زمانی که چندین app در پروژه دارید بسیار مهم است.

در فایل settings.py، بخش TEMPLATES تنظیمات مربوط به قالب‌ها را مدیریت می‌کند. به صورت پیش‌فرض، django دنبال پوشه‌ای به نام templates در هر app می‌گردد. برای اضافه‌کردن مسیر سراسری به قالب‌ها (مثلا اگر یک پوشه templates در ریشه پروژه دارید)، کد زیر را در DIRS وارد کنید:

from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates'],  # global templates directory
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

با فعال‌کردن APP_DIRS: True، جنگو قالب‌های موجود در فولدر templates درون هر app را به‌صورت خودکار پیدا می‌کند. همچنین با تعیین DIRS می‌توانید مسیرهای سفارشی نیز تعریف کنید. هنگام استفاده از این قالب‌ها در view، با تابع render می‌توانید قالب را فراخوانی کنید:

from django.shortcuts import render

def home_view(request):
    return render(request, 'home.html')  # looks in 'templates/home.html'

اگر پروژه‌ای دارید که از چند app و قالب مشترک یا عمومی استفاده می‌کند، مدیریت دقیق مسیرهای قالب‌ها بسیار مهم می‌شود. در چنین پروژه‌هایی میتوانید از چندین مسیر در DIRS استفاده کنید و قالب‌ها را به صورت ماژولار سازمان‌دهی کنید. این ساختار کمک میکند پروژه قابلیت توسعه بالاتری داشته باشد.

 

تفاوت مسیرهای نسبی و مطلق در تنظیمات Django

در تنظیمات پروژه django، مخصوصا برای فایل‌ها مثل static، media یا templates، مشخص‌کردن مسیر درست اهمیت زیادی دارد. مسیر نسبی یا relative مسیری است که نسبت به محل اجرای برنامه یا فایل جاری تعریف می‌شود، اما مسیر مطلق یا absolute مسیر کاملی است که از روت پروژه شروع می‌شود. استفاده نادرست از مسیرها ممکن است باعث شود فایل‌ها پیدا نشوند یا در محیط‌های مختلف رفتار متفاوتی داشته باشند.

در django برای جلوگیری از مشکلات ناشی از مسیرهای نسبی، از مسیرهای مطلق با استفاده از متغیری مثل BASE_DIR استفاده می‌شود. این متغیر در ابتدای settings.py تعریف می‌شود و مسیر روت پروژه را مشخص می‌کند. از این مسیر به‌صورت ترکیبی با Path یا os.path.join برای ساخت مسیرهای مطلق استفاده می‌شود. مثال:

from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

STATIC_ROOT = BASE_DIR / 'staticfiles'  # absolute path

در مقابل، اگر بنویسید STATIC_ROOT = 'staticfiles'، جنگو مسیر را نسبت به محل اجرای manage.py در نظر می‌گیرد که می‌تواند در برخی شرایط باعث خطا شود. مسیر نسبی در برخی اسکریپت‌های ساده یا پروژه‌های تستی مفید است، اما در محیط‌های production و پروژه‌های پیچیده، استفاده از مسیرهای مبتنی بر BASE_DIR توصیه می‌شود.

همچنین وقتی پروژه را به سرور دیگری منتقل می‌کنید یا از ابزارهای اتوماسیون مثل docker استفاده می‌کنید، مسیرهای مطلق تضمین می‌کنند که تنظیمات به مسیر صحیح در فایل‌سیستم اشاره دارند. این اصل یکی از دلایل مهم استفاده از pathlib و BASE_DIR در تمام مسیرهای پروژه django است.

 

نکات امنیتی در تعریف مسیرها

وقتی مسیرهای فایل‌ها مثل static، media و templates را در django تعریف می‌کنیم، رعایت نکات امنیتی بسیار حیاتی است تا از دسترسی غیرمجاز و نفوذ به سیستم جلوگیری شود. اولین اصل این است که مسیرهای تعریف شده نباید به گونه‌ای باشند که کاربران بتوانند به فایل‌های حساس یا بخش‌های اصلی پروژه دسترسی مستقیم پیدا کنند. به عنوان مثال، پوشه media که محل ذخیره فایل‌های آپلود شده توسط کاربر است، نباید به طور کامل بدون محدودیت در دسترس باشد.

دومین نکته مهم، جداسازی محیط توسعه و اجراست. در حالت development می‌توانیم مسیرها را به راحتی باز کنیم اما در production باید با استفاده از وب‌سرورهایی مثل nginx یا apache دسترسی‌ها را محدود کنیم و تنها مسیرهای لازم سرو شوند. به‌عنوان مثال، فایل‌های static و media باید فقط برای خواندن قابل دسترس باشند و هیچ امکانی برای اجرای کد یا نوشتن در آن‌ها فراهم نشود.

سوم اینکه نباید مسیرها را به صورت مستقیم از ورودی‌های کاربر یا متغیرهای غیر مطمئن ساخت، زیرا این کار می‌تواند به حملات مسیر traversal منجر شود که در آن مهاجم قادر است به فایل‌های خارج از محدوده تعریف‌شده دسترسی پیدا کند. بنابراین همیشه مسیرهای ثابت و کنترل‌شده تعریف کنید و اگر نیاز به دریافت مسیر از کاربر دارید، آن را به دقت اعتبارسنجی کنید. همچنین استفاده از توابع استاندارد django و ماژول pathlib برای مدیریت مسیرها باعث جلوگیری از خطاها و آسیب‌پذیری‌ها می‌شود.

 

مدیریت مسیرها در محیط‌های مختلف (Local, Production, etc)

در پروژه‌های django، محیط‌های مختلف مثل local و production نیازمند تنظیمات متفاوتی برای مسیرها هستند. دلیل اصلی این تفاوت، شرایط مختلف برای اجرای پروژه است. در محیط local معمولا مسیرها ساده‌تر و دسترسی‌ها بازتر است، اما در production باید امنیت و کارایی را جدی گرفت و مسیرها به دقت تعریف شوند.

برای مدیریت این تفاوت‌ها، بهترین روش استفاده از متغیرهای محیطی یا environment variables است. مثلا می‌توان دو فایل settings_local.py و settings_production.py داشت که هرکدام مسیرهای خاص خود را دارند و بر اساس محیط اجرا یکی از آن‌ها بارگذاری می‌شود. به این صورت در local مسیرهای static و media معمولا به صورت دایرکتوری‌های محلی مشخص می‌شوند، اما در production ممکن است این مسیرها به یک سرور فایل اختصاصی، CDN یا سرویس‌های ابری مثل amazon s3 اشاره کنند.

مثال ساده استفاده از متغیر محیطی برای تعیین مسیر:

import os
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

if os.getenv('DJANGO_ENV') == 'production':
    STATIC_ROOT = '/var/www/example.com/static/'
    MEDIA_ROOT = '/var/www/example.com/media/'
else:
    STATIC_ROOT = BASE_DIR / 'staticfiles'
    MEDIA_ROOT = BASE_DIR / 'media'

STATIC_URL = '/static/'
MEDIA_URL = '/media/'

این شیوه باعث میشود که نیاز به تغییر دستی تنظیمات هنگام انتقال پروژه نداشته باشیم. همچنین در production اغلب از وب‌سرورهای مجزا برای سرو فایل‌ها استفاده می‌شود که مسیرها و دسترسی‌ها در آن‌ها جداگانه تنظیم می‌شوند و django فقط وظیفه مدیریت پروژه را دارد. بنابراین تفکیک مسیرها و استفاده از متغیرهای محیطی کلید اصلی برای مدیریت هوشمند مسیرها در پروژه‌های django است.

 

خطاهای رایج در مسیردهی و نحوه رفع آن‌ها

یکی از مشکلات پرتکرار هنگام تنظیم مسیرهای static، media و templates در django، عدم نمایش یا بارگذاری فایل‌هاست. این موضوع معمولا ناشی از تعریف نادرست مسیرها یا کانفیگ اشتباه است. یکی از خطاهای رایج، استفاده از مسیرهای نسبی به جای مسیرهای مطلق مبتنی بر BASE_DIR است که باعث میشود django نتواند فایل‌ها را در محیط‌های مختلف پیدا کند. برای رفع این مشکل، همیشه مسیرها را با BASE_DIR و pathlib بسازید تا مسیرهای مطلق و دقیق باشند.

خطای دیگر، فراموش‌کردن اضافه‌کردن خطوط مربوط به سرو کردن فایل‌های static و media در urls.py هنگام توسعه است. بدون این تنظیم، django قادر به نمایش این فایل‌ها نیست. برای حل آن، در صورت فعال بودن DEBUG، باید از django.conf.urls.static.static استفاده کنید تا مسیرهای سرو فایل‌ها به urlها اضافه شوند.

همچنین، در زمان اجرای دستور collectstatic برای جمع‌آوری فایل‌های static، اگر مسیر STATIC_ROOT اشتباه یا دسترسی نوشتن به آن پوشه وجود نداشته باشد، فرایند با خطا مواجه می‌شود. بنابراین قبل از اجرای دستور، اطمینان حاصل کنید مسیر STATIC_ROOT صحیح و پوشه وجود دارد یا django اجازه ساخت آن را دارد.

خطاهای مربوط به مجوزهای دسترسی فایل‌ها یا پوشه‌ها را فراموش نکنید. در محیط‌های production اگر وب‌سرور اجازه خواندن یا نوشتن مسیرهای تعریف‌شده را نداشته باشد، فایل‌ها به درستی سرو نمی‌شوند. بنابراین تنظیم مجوزهای مناسب و بررسی لاگ‌های وب‌سرور از گام‌های مهم رفع خطا است.

رعایت این نکات و تست تنظیمات در محیط‌های مختلف باعث میشود خطاهای رایج مسیردهی در django به حداقل برسد.

 

در مجموع، مدیریت مسیرها در django به کمک BASE_DIR و ابزارهای استاندارد پایتون مانند pathlib، امکان ساخت پروژه‌ای قابل حمل، امن و سازمان‌یافته را فراهم می‌کند. توجه به نکات امنیتی، تفاوت‌های محیط‌های توسعه و اجرا، و رفع خطاهای رایج در مسیردهی، کلید موفقیت در ایجاد پروژه‌های پایدار و بدون مشکل خواهد بود. رعایت این اصول، تجربه توسعه و نگهداری پروژه را بسیار بهبود می‌بخشد.

تشکر از اینکه در این پست همراه با گوبلشت بودید. امیدواریم برای شما مفید واقع شده باشد.

 


avatar

محمدمهدی کریمه

برنامه‌نویس و نویسنده بلاگ
نوشته های نویسنده

عاشق ساده‌سازی مفاهیم سخت؛ می‌نویسم تا یاد بگیرم و یاد بدهم.


0 دیدگاه

لطفا برای ارسال کامنت وارد حساب کاربری خود شوید