📁 فصل ۸: فایلهای Static و Media
یاد بگیر چطور CSS، JS، تصاویر و فایلهای آپلودی رو در جنگو مدیریت کنی.
یاد بگیر چطور CSS، JS، تصاویر و فایلهای آپلودی رو در جنگو مدیریت کنی.
📑 فهرست این فصل
🎯 تفاوت Static و Media
📦 Static
فایلهای ثابت توسعهدهنده
- CSS
- JavaScript
- تصاویر سایت (لوگو، آیکون)
- فونتها
قبل از دیپلوی، توسعهدهنده اضافه میکنه
🖼️ Media
فایلهای آپلودی کاربر
- تصویر پروفایل
- تصاویر محصولات
- فایلهای PDF
- فایلهای صوتی
کاربر در زمان استفاده آپلود میکنه
📦 فایلهای Static
تنظیمات
import os
# URL برای دسترسی به فایلها
STATIC_URL = '/static/'
# پوشههای اضافی برای فایلهای static (در حالت توسعه)
STATICFILES_DIRS = [
BASE_DIR / 'static',
]
# پوشه نهایی برای جمعآوری در production
STATIC_ROOT = BASE_DIR / 'staticfiles'
ساختار پوشه
myproject/
├── manage.py
├── static/ # ← static کلی پروژه
│ ├── css/
│ │ └── main.css
│ ├── js/
│ │ └── app.js
│ └── images/
│ └── logo.png
├── products/
│ ├── static/ # ← static اپ خاص
│ │ └── products/
│ │ └── style.css
│ └── ...
└── ...
استفاده در قالب
{% load static %}
<link rel="stylesheet" href="{% static 'css/main.css' %}">
<script src="{% static 'js/app.js' %}"></script>
<img src="{% static 'images/logo.png' %}" alt="لوگو">
{# با متغیر #}
<img src="{% static image_path %}" alt="...">
collectstatic – برای دیپلوی
قبل از دیپلوی، همه فایلهای static رو در یک پوشه جمع میکنیم:
python manage.py collectstatic
در production، سرور وب (Nginx) نباید با جنگو درگیر بشه برای فایلهای ثابت. بهتره همه فایلهای static رو یکجا جمع کنیم تا Nginx مستقیم سرو کنه.
🖼️ فایلهای Media
تنظیمات
# URL برای دسترسی
MEDIA_URL = '/media/'
# مسیر فیزیکی فایلها
MEDIA_ROOT = BASE_DIR / 'media'
تنظیم URL برای حالت توسعه
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path
urlpatterns = [
path('admin/', admin.site.urls),
# ...
]
# فقط در حالت DEBUG=True
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
📸 کار با ImageField
نصب Pillow
برای کار با تصاویر، نیاز به کتابخانه Pillow داریم:
pip install Pillow
تعریف فیلد در مدل
class Product(models.Model):
name = models.CharField(max_length=200)
# تصویر اصلی
image = models.ImageField(
upload_to='products/',
blank=True,
null=True,
verbose_name='تصویر محصول'
)
# با تاریخ - مرتبسازی خودکار
image_dated = models.ImageField(
upload_to='products/%Y/%m/%d/',
blank=True
)
# فایل
catalog = models.FileField(
upload_to='catalogs/',
blank=True
)
استفاده در قالب
{% if product.image %}
<img src="{{ product.image.url }}" alt="{{ product.name }}">
</p>
<p>مسیر: {{ product.image.url }}</p>
<p>اندازه: {{ product.image.size|filesizeformat }}</p>
<p>عرض: {{ product.image.width }}</p>
<p>ارتفاع: {{ product.image.height }}</p>
{% else %}
<img src="{% static 'images/no-image.png' %}" alt="بدون تصویر">
{% endif %}
تابع upload_to پویا
اگه میخوای مسیر آپلود رو خودت تعیین کنی:
def product_image_path(instance, filename):
# filename اسم اصلی فایله
# instance آبجکت محصوله
return f'products/{instance.category.slug}/{instance.id}/{filename}'
class Product(models.Model):
name = models.CharField(max_length=200)
image = models.ImageField(upload_to=product_image_path)
🖼️ ساخت تامبنیل
برای کاهش حجم تصاویر، میتونیم تامبنیل بسازیم:
روش ۱: با Pillow در مدل
from PIL import Image
from django.db import models
class Product(models.Model):
image = models.ImageField(upload_to='products/')
def save(self, *args, **kwargs):
super().save(*args, **kwargs) # اول ذخیره
if self.image:
img = Image.open(self.image.path)
# تغییر اندازه اگه بزرگتر از ۸۰۰x۸۰۰ بود
if img.height > 800 or img.width > 800:
output_size = (800, 800)
img.thumbnail(output_size)
img.save(self.image.path, quality=85, optimize=True)
روش ۲: استفاده از کتابخانه easy-thumbnails
pip install easy-thumbnails
INSTALLED_APPS = [
# ...
'easy_thumbnails',
]
THUMBNAIL_ALIASES = {
'': {
'small': {'size': (100, 100), 'crop': True},
'medium': {'size': (300, 300), 'crop': True},
'large': {'size': (800, 600)},
},
}
{% load thumbnail %}
{# ساخت تامبنیل با اندازه دلخواه #}
<img src="{% thumbnail product.image 200x200 crop %}" alt="...">
{# با alias تعریفشده در settings #}
<img src="{% thumbnail product.image 'small' %}" alt="...">
🎯 مثالهای کاربردی
مثال ۱: لوگو و فاوآیکون سایت
{% load static %}
<!DOCTYPE html>
<html>
<head>
<link rel="icon" href="{% static 'images/favicon.ico' %}">
<link rel="stylesheet" href="{% static 'css/style.css' %}">
</head>
<body>
<header>
<img src="{% static 'images/logo.png' %}" alt="ICSD" height="50">
</header>
<script src="{% static 'js/main.js' %}"></script>
</body>
</html>
مثال ۲: گالری تصاویر محصول
class Product(models.Model):
name = models.CharField(max_length=200)
main_image = models.ImageField(upload_to='products/')
class ProductImage(models.Model):
product = models.ForeignKey(
Product,
related_name='images',
on_delete=models.CASCADE
)
image = models.ImageField(upload_to='products/gallery/')
alt_text = models.CharField(max_length=200, blank=True)
order = models.IntegerField(default=0)
class Meta:
ordering = ['order']
<div class="main-image">
<img src="{{ product.main_image.url }}" id="mainImage">
</div>
<div class="thumbnails">
{% for img in product.images.all %}
<img
src="{{ img.image.url }}"
alt="{{ img.alt_text }}"
onclick="document.getElementById('mainImage').src=this.src"
class="thumb">
{% endfor %}
</div>
مثال ۳: واترمارک خودکار + تامبنیل
from PIL import Image
from io import BytesIO
from django.core.files.uploadedfile import InMemoryUploadedFile
from django.db import models
import sys
class Product(models.Model):
name = models.CharField(max_length=200)
image = models.ImageField(upload_to='products/')
thumbnail = models.ImageField(upload_to='products/thumbs/', blank=True)
def save(self, *args, **kwargs):
# پردازش تصویر اصلی
if self.image:
img = Image.open(self.image)
# واترمارک
self._add_watermark(img)
# ذخیره با کیفیت
output = BytesIO()
img.save(output, format='JPEG', quality=90, optimize=True)
output.seek(0)
self.image = InMemoryUploadedFile(
output, 'ImageField',
f'{self.image.name.split(".")[0]}.jpg',
'image/jpeg', sys.getsizeof(output), None
)
super().save(*args, **kwargs)
# ساخت تامبنیل بعد از ذخیره
if self.image and not self.thumbnail:
self._create_thumbnail()
def _add_watermark(self, img):
from PIL import ImageDraw, ImageFont
draw = ImageDraw.Draw(img)
text = 'ICSD.IR'
# اضافه کردن متن گوشه پایین
draw.text(
(img.width - 150, img.height - 30),
text,
fill=(255, 255, 255, 128)
)
def _create_thumbnail(self):
img = Image.open(self.image.path)
img.thumbnail((300, 300))
thumb_path = self.image.path.replace('products/', 'products/thumbs/')
img.save(thumb_path)
self.thumbnail.name = self.image.name.replace('products/', 'products/thumbs/')
super().save(update_fields=['thumbnail'])
📝 تمرینها
تمرین ۱
یه قالب پایه بساز که فایل CSS و JS سایتت رو از پوشه static بارگذاری کنه.
تمرین ۲
یه مدل UserProfile بساز که فیلد avatar داشته باشه. در قالب نمایش بده. اگه عکس نداشت، عکس پیشفرض از static نشون بده.
تمرین ۳
یه سیستم آپلود تصویر بساز که قبل از ذخیره: ۱) اندازه رو به حداکثر ۱۰۰۰ پیکسل برسونه ۲) واترمارک اضافه کنه ۳) تامبنیل ۲۰۰x۲۰۰ بسازه.