\n\n\n# Содержимое static/css/style.css\nbody {\n font-family: Arial, sans-serif;\n background-color: #f5f5f5;\n}\n```\n\n#### Media files\n\n```python\n# models.py (Django)\nfrom django.db import models\n\nclass UserProfile(models.Model):\n user = models.OneToOneField(User, on_delete=models.CASCADE)\n avatar = models.ImageField(upload_to='avatars/') # В media/\n bio_document = models.FileField(upload_to='documents/') # В media/\n\n# settings.py\nMEDIA_URL = '/media/'\nMEDIA_ROOT = os.path.join(BASE_DIR, 'media') # Где хранить\n\n# urls.py (для локальной разработки)\nfrom django.conf import settings\nfrom django.conf.urls.static import static\n\nurlpatterns = [...]\n\nif settings.DEBUG:\n urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)\n\n# В шаблоне\n\n\n\nDownload Bio\n\n```\n\n### Сравнительная таблица\n\n| Параметр | Static files | Media files |\n|----------|-------------|-------------|\n| Кто создаёт | Разработчик | Пользователь |\n| Как хранятся | В репозитории (git) | В папке media/ |\n| Когда меняются | При деплое | Постоянно (при загрузках) |\n| Версионирование | Git отслеживает | Не отслеживается |\n| CDN кэширование | ✅ Можно кэшировать | ❌ Проблематично |\n| Размер | Малый (обычно) | Большой (фотографии) |\n| Примеры | CSS, JS, логотипы | Аватары, документы |\n| Доступ | Всем пользователям | Разные права доступа |\n| URL | /static/... | /media/... |\n| Backup | Есть в репозитории | Отдельно |\n\n### Инициализация файлов\n\n#### Static files — фиксированные\n\n```python\n# project/static/css/style.css создан один раз\n/* Будет одинаковым для всех пользователей */\nbody {\n background: white;\n font-family: Arial;\n}\n\n# Версионирование через Django\n# settings.py\nSTATIC_URL = '/static/'\nSTATIC_VERSION = '1.2.3' # Для кэширования браузером\n\n# Шаблон\n\n```\n\n#### Media files — динамические\n\n```python\n# model upload_to parameter\nclass BlogPost(models.Model):\n image = models.ImageField(upload_to='blog_images/%Y/%m/%d/')\n # Сохранится как: media/blog_images/2024/03/22/image.jpg\n\n# В views\nif request.method == 'POST':\n image = request.FILES['image']\n post = BlogPost.objects.create(\n image=image\n )\n # Django автоматически сохраняет в media/\n```\n\n### Обслуживание файлов в продакшене\n\n#### Static files — через веб-сервер\n\n```bash\n# 1. Собираем все static файлы\npython manage.py collectstatic\n# Копирует из app/static в STATIC_ROOT\n\n# 2. Nginx конфиг\nlocation /static/ {\n alias /home/app/staticfiles/; # Прямая отдача файлов\n expires 30d; # Кэширование на 30 дней\n}\n\n# Результат: очень быстро, не нагружает Django\n```\n\n#### Media files — проблематично\n\n```bash\n# Вариант 1: Через Nginx (если доверяешь загрузчикам)\nlocation /media/ {\n alias /home/app/media/; # Риск безопасности!\n # Пользователь может загрузить .php и выполнить код\n}\n\n# Вариант 2: Через Django (безопасно, медленно)\nlocation /media/ {\n proxy_pass http://127.0.0.1:8000; # Через Django\n}\n# Django может проверить права доступа\n\n# Вариант 3: Через облако (лучше)\n# AWS S3, Google Cloud Storage, etc.\nDEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'\n```\n\n### Контроль доступа\n\n#### Static files — всем доступны\n\n```python\n# Все пользователи видят одинаковые файлы\n # Доступно всем\n # Доступно всем\n```\n\n#### Media files — нужна проверка прав\n\n```python\n# views.py\nfrom django.views.static import serve\nfrom django.http import Http404\nimport os\n\ndef serve_media(request, file_path):\n # Проверяем права доступа\n obj = MyModel.objects.get(file_path=file_path)\n \n if not obj.is_accessible_by(request.user):\n raise Http404(\"File not found\")\n \n return serve(\n request,\n file_path,\n document_root=settings.MEDIA_ROOT\n )\n\n# urls.py\nurlpatterns = [\n path('media/', serve_media),\n]\n\n# Только авторизованные пользователи видят свои файлы\n```\n\n### Безопасность\n\n#### Static files — безопасны\n\n```python\n# Разработчик контролирует содержимое\n# Нет риска выполнения вредоносного кода\n# Можно безопасно отдавать через Nginx\n```\n\n#### Media files — уязвимы\n\n```python\n# Опасность 1: Загрузка вредоносного файла\nfile = request.FILES['image']\n# Пользователь загружает malicious.php\n\n# Защита: валидируем типы файлов\nfrom django.core.validators import FileExtensionValidator\n\nclass Document(models.Model):\n file = models.FileField(\n upload_to='documents/',\n validators=[FileExtensionValidator(\n allowed_extensions=['pdf', 'doc', 'docx']\n )]\n )\n\n# Опасность 2: Path traversal\n# Пользователь пытается скачать чужой файл\nfile_path = request.GET['file'] # ../../admin_secret.pdf\n\n# Защита: используй models с правами доступа\nobj = Document.objects.get(id=file_id)\nif not obj.is_owned_by(request.user):\n raise Http404()\n\n# Опасность 3: Исполнение кода\n# Если файл .php находится в веб-доступной папке\n\n# Защита: отдавай файлы через Django или облако\n# Не отдавай напрямую через Nginx\n```\n\n### Реальные примеры\n\n#### Полная настройка Django\n\n```python\n# settings.py\nimport os\nfrom pathlib import Path\n\nBASE_DIR = Path(__file__).resolve().parent.parent\n\n# Static files\nSTATIC_URL = '/static/'\nSTATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')\nSTATICFILES_DIRS = [\n os.path.join(BASE_DIR, 'static'),\n]\n\n# Media files\nMEDIA_URL = '/media/'\nMEDIA_ROOT = os.path.join(BASE_DIR, 'media')\n\n# urls.py\nfrom django.conf import settings\nfrom django.conf.urls.static import static\n\nurlpatterns = [\n # ... ваши URLs\n]\n\nif settings.DEBUG:\n urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)\n urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)\n\n# Production: Nginx обслуживает static, Django обслуживает media\n```\n\n#### Загрузка файла с валидацией\n\n```python\n# models.py\nfrom django.core.files.uploadhandlers import TemporaryFileUploadHandler\n\nclass UserAvatar(models.Model):\n user = models.OneToOneField(User, on_delete=models.CASCADE)\n image = models.ImageField(\n upload_to='avatars/%Y/%m/%d/',\n validators=[\n FileExtensionValidator(\n allowed_extensions=['jpg', 'jpeg', 'png']\n )\n ]\n )\n \n def clean(self):\n # Проверяем размер\n if self.image.size > 5 * 1024 * 1024: # 5MB\n raise ValidationError(\"Image too large\")\n \n # Проверяем размеры изображения\n img = Image.open(self.image)\n if img.width < 100 or img.height < 100:\n raise ValidationError(\"Image too small\")\n\n# views.py\ndef upload_avatar(request):\n if request.method == 'POST':\n avatar = UserAvatar(\n user=request.user,\n image=request.FILES['avatar']\n )\n avatar.full_clean() # Валидируем\n avatar.save() # Сохраняем\n return redirect('profile')\n```\n\n### Best Practice\n\n```python\n# 1. Static files — только в разработке\n# Production: через Nginx с expires header\nlocation /static/ {\n alias /staticfiles/;\n expires 30d;\n add_header Cache-Control \"public, immutable\";\n}\n\n# 2. Media files — через облако\nDEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'\n\n# 3. Валидируй всё\nfrom django.core.validators import FileExtensionValidator\n\n# 4. Отдавай через Django если нужны права доступа\n# Отдавай через Nginx если публичные\n\n# 5. Используй CDN для static\n# CloudFront, Cloudflare, etc.\n\n# 6. Регулярно чисти media\n# Удаляй старые загрузки, проверяй квоту\n```\n","dateCreated":"2026-03-22T15:39:23.252784","upvoteCount":0,"author":{"@type":"Person","name":"claude-haiku-4.5"}}}}
← Назад к вопросам

В чём разница между static files и media files?

1.0 Junior🔥 141 комментариев
#Django

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между static files и media files

Основные определения

  • Static files — файлы, созданные разработчиком и поставляемые с приложением (CSS, JS, изображения логотипов, шрифты)
  • Media files — файлы, загруженные пользователями (аватары, документы, фотографии)
Структура проекта Django:
project/
├── static/          <- Статичные файлы (разработчик создал)
│   ├── css/
│   ├── js/
│   └── images/
├── media/           <- Медиа файлы (пользователи загрузили)
│   ├── avatars/
│   ├── documents/
│   └── uploads/
└── manage.py

Практические примеры

Static files

# settings.py (Django)
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')  # Для продакшена

# В шаблоне
{% load static %}
<link rel="stylesheet" href="{% static 'css/style.css' %}">
<script src="{% static 'js/app.js' %}"></script>
<img src="{% static 'images/logo.png' %}">

# Содержимое static/css/style.css
body {
    font-family: Arial, sans-serif;
    background-color: #f5f5f5;
}

Media files

# models.py (Django)
from django.db import models

class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    avatar = models.ImageField(upload_to='avatars/')  # В media/
    bio_document = models.FileField(upload_to='documents/')  # В media/

# settings.py
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')  # Где хранить

# urls.py (для локальной разработки)
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [...]

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

# В шаблоне
<img src="{{ user.profile.avatar.url }}">
<!-- Результат: <img src="/media/avatars/user123_avatar.jpg"> -->

<a href="{{ user.profile.bio_document.url }}">Download Bio</a>
<!-- Результат: <a href="/media/documents/resume_2024.pdf">Download Bio</a> -->

Сравнительная таблица

ПараметрStatic filesMedia files
Кто создаётРазработчикПользователь
Как хранятсяВ репозитории (git)В папке media/
Когда меняютсяПри деплоеПостоянно (при загрузках)
ВерсионированиеGit отслеживаетНе отслеживается
CDN кэширование✅ Можно кэшировать❌ Проблематично
РазмерМалый (обычно)Большой (фотографии)
ПримерыCSS, JS, логотипыАватары, документы
ДоступВсем пользователямРазные права доступа
URL/static/.../media/...
BackupЕсть в репозиторииОтдельно

Инициализация файлов

Static files — фиксированные

# project/static/css/style.css создан один раз
/* Будет одинаковым для всех пользователей */
body {
    background: white;
    font-family: Arial;
}

# Версионирование через Django
# settings.py
STATIC_URL = '/static/'
STATIC_VERSION = '1.2.3'  # Для кэширования браузером

# Шаблон
<link rel="stylesheet" href="{% static 'css/style.css' %}?v={{ STATIC_VERSION }}">

Media files — динамические

# model upload_to parameter
class BlogPost(models.Model):
    image = models.ImageField(upload_to='blog_images/%Y/%m/%d/')
    # Сохранится как: media/blog_images/2024/03/22/image.jpg

# В views
if request.method == 'POST':
    image = request.FILES['image']
    post = BlogPost.objects.create(
        image=image
    )
    # Django автоматически сохраняет в media/

Обслуживание файлов в продакшене

Static files — через веб-сервер

# 1. Собираем все static файлы
python manage.py collectstatic
# Копирует из app/static в STATIC_ROOT

# 2. Nginx конфиг
location /static/ {
    alias /home/app/staticfiles/;  # Прямая отдача файлов
    expires 30d;  # Кэширование на 30 дней
}

# Результат: очень быстро, не нагружает Django

Media files — проблематично

# Вариант 1: Через Nginx (если доверяешь загрузчикам)
location /media/ {
    alias /home/app/media/;  # Риск безопасности!
    # Пользователь может загрузить .php и выполнить код
}

# Вариант 2: Через Django (безопасно, медленно)
location /media/ {
    proxy_pass http://127.0.0.1:8000;  # Через Django
}
# Django может проверить права доступа

# Вариант 3: Через облако (лучше)
# AWS S3, Google Cloud Storage, etc.
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'

Контроль доступа

Static files — всем доступны

# Все пользователи видят одинаковые файлы
<img src="/static/images/logo.png">  # Доступно всем
<script src="/static/js/app.js"></script>  # Доступно всем

Media files — нужна проверка прав

# views.py
from django.views.static import serve
from django.http import Http404
import os

def serve_media(request, file_path):
    # Проверяем права доступа
    obj = MyModel.objects.get(file_path=file_path)
    
    if not obj.is_accessible_by(request.user):
        raise Http404("File not found")
    
    return serve(
        request,
        file_path,
        document_root=settings.MEDIA_ROOT
    )

# urls.py
urlpatterns = [
    path('media/<path:file_path>', serve_media),
]

# Только авторизованные пользователи видят свои файлы

Безопасность

Static files — безопасны

# Разработчик контролирует содержимое
# Нет риска выполнения вредоносного кода
# Можно безопасно отдавать через Nginx

Media files — уязвимы

# Опасность 1: Загрузка вредоносного файла
file = request.FILES['image']
# Пользователь загружает malicious.php

# Защита: валидируем типы файлов
from django.core.validators import FileExtensionValidator

class Document(models.Model):
    file = models.FileField(
        upload_to='documents/',
        validators=[FileExtensionValidator(
            allowed_extensions=['pdf', 'doc', 'docx']
        )]
    )

# Опасность 2: Path traversal
# Пользователь пытается скачать чужой файл
file_path = request.GET['file']  # ../../admin_secret.pdf

# Защита: используй models с правами доступа
obj = Document.objects.get(id=file_id)
if not obj.is_owned_by(request.user):
    raise Http404()

# Опасность 3: Исполнение кода
# Если файл .php находится в веб-доступной папке

# Защита: отдавай файлы через Django или облако
# Не отдавай напрямую через Nginx

Реальные примеры

Полная настройка Django

# settings.py
import os
from pathlib import Path

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

# Static files
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static'),
]

# Media files
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

# 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)
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

# Production: Nginx обслуживает static, Django обслуживает media

Загрузка файла с валидацией

# models.py
from django.core.files.uploadhandlers import TemporaryFileUploadHandler

class UserAvatar(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    image = models.ImageField(
        upload_to='avatars/%Y/%m/%d/',
        validators=[
            FileExtensionValidator(
                allowed_extensions=['jpg', 'jpeg', 'png']
            )
        ]
    )
    
    def clean(self):
        # Проверяем размер
        if self.image.size > 5 * 1024 * 1024:  # 5MB
            raise ValidationError("Image too large")
        
        # Проверяем размеры изображения
        img = Image.open(self.image)
        if img.width < 100 or img.height < 100:
            raise ValidationError("Image too small")

# views.py
def upload_avatar(request):
    if request.method == 'POST':
        avatar = UserAvatar(
            user=request.user,
            image=request.FILES['avatar']
        )
        avatar.full_clean()  # Валидируем
        avatar.save()  # Сохраняем
        return redirect('profile')

Best Practice

# 1. Static files — только в разработке
# Production: через Nginx с expires header
location /static/ {
    alias /staticfiles/;
    expires 30d;
    add_header Cache-Control "public, immutable";
}

# 2. Media files — через облако
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'

# 3. Валидируй всё
from django.core.validators import FileExtensionValidator

# 4. Отдавай через Django если нужны права доступа
# Отдавай через Nginx если публичные

# 5. Используй CDN для static
# CloudFront, Cloudflare, etc.

# 6. Регулярно чисти media
# Удаляй старые загрузки, проверяй квоту