add: пред-прод контейнер
This commit is contained in:
10
.env.sample
10
.env.sample
@@ -117,6 +117,16 @@ LOG_LEVEL=INFO
|
||||
# CELERY_BROKER_URL=redis://localhost:6379/0
|
||||
# CELERY_RESULT_BACKEND=redis://localhost:6379/0
|
||||
|
||||
# ============================================================================
|
||||
# DOCKER: LOCAL PRODUCTION TESTING
|
||||
# ============================================================================
|
||||
|
||||
# Разрешить Django обслуживать медиа-файлы через Python (только для локального тестирования)
|
||||
# ВАЖНО: В настоящем production медиа и статику обслуживает Nginx, а не Django!
|
||||
# Используется ТОЛЬКО в docker-compose.local-prod.yml для локального тестирования production конфигурации.
|
||||
# На production сервере НЕ устанавливайте это значение в True!
|
||||
ALLOW_MEDIA_SERVE=False
|
||||
|
||||
# ============================================================================
|
||||
# ИНСТРУКЦИЯ ПО ИСПОЛЬЗОВАНИЮ
|
||||
# ============================================================================
|
||||
|
||||
72
.gitea/workflows/docker-publish.yaml
Normal file
72
.gitea/workflows/docker-publish.yaml
Normal file
@@ -0,0 +1,72 @@
|
||||
name: Build and Push Docker Image
|
||||
run-name: Build and Push Docker Image ${{ github.ref_name }}
|
||||
|
||||
on:
|
||||
push:
|
||||
# Запускать сборку только при создании тега, начинающегося с 'v' (например, v1.0.0, v2.3.1)
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
env:
|
||||
REGISTRY: git.cube2.ru
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
runs-on: ubuntu-latest # Или метка вашего раннера, если он специфичный (например, macos или self-hosted)
|
||||
container:
|
||||
image: catthehacker/ubuntu:act-latest
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# Настройка QEMU для мультиплатформенной сборки (если нужно собирать под разные архитектуры)
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
||||
# Настройка Docker Buildx (обязательно для build-push-action)
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
# Логин в реестр Gitea
|
||||
- name: Log in to the Container registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
|
||||
# Извлечение метаданных (тегов и лейблов) для Docker
|
||||
- name: Extract metadata (tags, labels) for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=ref,event=tag
|
||||
type=raw,value=latest,enable=${{ github.ref_type == 'tag' }}
|
||||
|
||||
# Сборка и отправка образа
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile
|
||||
push: true
|
||||
# Собираем под текущую архитектуру (linux/amd64).
|
||||
# Если сервер и MacMini на разных архитектурах (x86 vs ARM), добавьте нужные, например: linux/amd64,linux/arm64
|
||||
# platforms: linux/amd64,linux/arm64
|
||||
# ---
|
||||
# Собираем только под linux/amd64 (для скорости + все равно сервер на x86).
|
||||
platforms: linux/amd64
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
# ДОБАВЛЕНО для медленного интернета и оптимизации сборки:
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
timeout: 1800 # Увеличено до 30 минут на всю сборку
|
||||
150
config/nginx/oknardia-app--external-nginx.conf
Normal file
150
config/nginx/oknardia-app--external-nginx.conf
Normal file
@@ -0,0 +1,150 @@
|
||||
# config/nginx/oknardia-app--external-nginx.conf
|
||||
# ==============================================================================
|
||||
# ЭТАЛОННЫЙ КОНФИГУРАЦИОННЫЙ ФАЙЛ NGINX (Reverse Proxy для Docker)
|
||||
# ==============================================================================
|
||||
#
|
||||
# ВНИМАНИЕ:
|
||||
# Этот файл является шаблоном. При первом деплое он копируется
|
||||
# в `/home/user/path-to-oknardia-app/config/nginx/oknardia-app--external-nginx.conf`,
|
||||
# а затем (уже на хосте, руками) через силинк в `/etc/nginx/sites-available/` и активируется.
|
||||
# При последующих деплоях `oknardia-app--external-nginx.conf` НЕ ПЕРЕЗАПИСЫВАЕТСЯ,
|
||||
# чтобы не затереть SSL-сертификаты и ручные правки.
|
||||
#
|
||||
# Если вы изменили этот файл в репозитории и хотите применить изменения на проде:
|
||||
# вам нужно обновить файл в `/home/user/path-to-oknardia-app/config/nginx/oknardia-app--external-nginx.conf` вручную (diff + copy).
|
||||
#
|
||||
# Так же (рядом) будет создан образец этого файла `nginx_oknardia.conf.example`, который будет обновляться при деплоях
|
||||
# из репозитория, чтобы вы могли видеть, что изменилось и при необходимости перенести эти изменения на прод.
|
||||
#
|
||||
# Предполагаемая структура на сервере:
|
||||
# /home/user/path-to-oknardia-app/
|
||||
# ├── docker-compose.yml
|
||||
# ├── .env
|
||||
# ├── media/ <-- Сюда Nginx смотрит напрямую (Docker volume)
|
||||
# └── ...
|
||||
|
||||
# 1. Описываем, где живет наш Django в Docker
|
||||
upstream oknardia-django {
|
||||
# Мы пробрасываем порт 8050 из контейнера наружу (в docker-compose.yml имя сервиса 'web', контейнер 'oknardia-backend')
|
||||
server 127.0.0.1:8060;
|
||||
keepalive_requests 200;
|
||||
}
|
||||
|
||||
# 2. Конфигурируем сервер
|
||||
server {
|
||||
server_name tmp.oknardia.ru; # Основное доменное имя
|
||||
|
||||
# Слушаем 80 порт (Certbot потом добавит сюда редирект на 443 и настройки SSL)
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
charset utf-8;
|
||||
client_max_body_size 10M; # Разрешаем загрузку не слишком больших картинок
|
||||
|
||||
# Логи (пути могут отличаться в зависимости от настроек сервера, здесь стандартные для Ubuntu)
|
||||
access_log /var/log/nginx/oknardia.access.log;
|
||||
error_log /var/log/nginx/oknardia.error.log;
|
||||
|
||||
# --- GZIP (Сжатие) ---
|
||||
# Очень важно для динамического HTML от Django, который Gunicorn отдает несжатым.
|
||||
gzip on;
|
||||
gzip_vary on; # Добавляет заголовок Vary: Accept-Encoding
|
||||
gzip_proxied any; # Сжимать ответы, даже если мы за прокси
|
||||
gzip_comp_level 6; # Оптимальный баланс скорость/сжатие
|
||||
gzip_min_length 1000; # Не сжимать совсем мелочь
|
||||
# Типы файлов для сжатия (HTML сжимается автоматически, его писать не нужно)
|
||||
gzip_types
|
||||
text/plain
|
||||
text/css
|
||||
text/xml
|
||||
text/javascript
|
||||
application/javascript
|
||||
application/json
|
||||
application/xml
|
||||
application/xml+rss
|
||||
image/svg+xml
|
||||
image/x-icon
|
||||
application/vnd.ms-fontobject
|
||||
font/woff
|
||||
font/woff2;
|
||||
|
||||
# --- МЕДИА ФАЙЛЫ (Загруженный контент) ---
|
||||
# Nginx отдает их напрямую с диска хоста, не дергая Docker.
|
||||
# Путь должен совпадать с тем, где лежит volume на хост-машине.
|
||||
# ВАЖНО: Убедитесь, что пользователь nginx (www-data) имеет права на чтение этой папки!
|
||||
# ТРЕБУЕТСЯ ЗАМЕНА ПРИ ДЕПЛОЕ: /home/user/path-to-oknardia-app -> ваш реальный путь
|
||||
location /media/ {
|
||||
alias /home/user/path-to-oknardia-app/media/;
|
||||
expires 30d; # Кешируем картинки на месяц
|
||||
add_header Cache-Control "public, no-transform";
|
||||
}
|
||||
|
||||
# --- СТРАНИЦЫ ОШИБОК (Custom Error Pages) ---
|
||||
# Если Django упал (502) или сработал тайм-аут (504), Nginx должен отдать статический HTML.
|
||||
# Эти файлы должны лежать в папке, доступной Nginx (например, в `media/_error`).
|
||||
#
|
||||
# ВАЖНО:
|
||||
# 1. Файлы 50x.html (500, 502, 503, 504) копируются в `media/_error` при старте контейнера (см. docker-compose.prod.yml -> command).
|
||||
# 2. error_page директива перехватывает ошибки от апстрима (Gunicorn).
|
||||
error_page 500 /500.html;
|
||||
error_page 502 /502.html;
|
||||
error_page 503 /503.html;
|
||||
error_page 504 /504.html;
|
||||
|
||||
location = /500.html { root /home/user/path-to-oknardia-app/media/_error; internal; }
|
||||
location = /502.html { root /home/user/path-to-oknardia-app/media/_error; internal; }
|
||||
location = /503.html { root /home/user/path-to-oknardia-app/media/_error; internal; }
|
||||
location = /504.html { root /home/user/path-to-oknardia-app/media/_error; internal; }
|
||||
|
||||
# 404 (и другие) тоже нужно кастомизировать... обычно Django сам отдает 404.
|
||||
# Но, например, Nginx отдаст 404 при ошике доступа к media-файлам (они храняться на хосте, а не в контейнере)
|
||||
error_page 400 /400.html;
|
||||
error_page 401 /401.html;
|
||||
error_page 403 /403.html;
|
||||
error_page 404 /404.html;
|
||||
error_page 413 /413.html;
|
||||
error_page 429 /429.html;
|
||||
|
||||
location = /400.html { root /home/user/path-to-oknardia-app/media/_error; internal; }
|
||||
location = /401.html { root /home/user/path-to-oknardia-app/media/_error; internal; }
|
||||
location = /403.html { root /home/user/path-to-oknardia-app/media/_error; internal; }
|
||||
location = /404.html { root /home/user/path-to-oknardia-app/media/_error; internal; }
|
||||
location = /413.html { root /home/user/path-to-oknardia-app/media/_error; internal; }
|
||||
location = /429.html { root /home/user/path-to-oknardia-app/media/_error; internal; }
|
||||
|
||||
# Указываем единую страницу (на реконструкции) для всех прочих ошибок
|
||||
error_page 405 406 407 408 409 410 411 412 414 415 416 417 418 421 422 423 424 425 426 428 431 451 /under_reconstruction.html;
|
||||
location = /under_reconstruction.html { root /home/user/path-to-oknardia-app/media/_error; internal; }
|
||||
|
||||
# --- ВСЁ ОСТАЛЬНОЕ (Django + WhiteNoise) ---
|
||||
# Статика (/static/), robots.txt, favicon.ico и сам сайт обрабатываются внутри контейнера.
|
||||
# Nginx просто прокидывает запрос внутрь.
|
||||
location / {
|
||||
proxy_pass http://oknardia-django;
|
||||
|
||||
# Передаем правильные заголовки, чтобы Django знал реальный IP и протокол
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
||||
# Если нужно чтобы Django обрабатывал и HTTP, и HTTPS, то можно раскомментировать эту строку
|
||||
# и передавать реальный протокол от клиента
|
||||
# proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# Явно указываем https, потому что клиент всегда приходит по HTTPS к Nginx
|
||||
# Даже если внутри контейнера это HTTP на 127.0.0.1:8050, для Django это должно быть HTTPS
|
||||
proxy_set_header X-Forwarded-Proto https;
|
||||
|
||||
# Тайм-ауты (важно для долгих операций, если они есть)
|
||||
proxy_read_timeout 180s;
|
||||
proxy_connect_timeout 180s;
|
||||
}
|
||||
}
|
||||
|
||||
# 3. Редирект с www на без-www (SEO best practice)
|
||||
server {
|
||||
server_name www.tmp.oknardia.ru;
|
||||
listen 80;
|
||||
return 301 $scheme://oknardia.ru$request_uri; # Всегда редиректим на основной домен
|
||||
}
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
# Разработка сайта OKNARDIA.RU
|
||||
# == Конфикурационный файл nginx oknardia.conf
|
||||
|
||||
# Описываем апстрим-потоки которые должен подключить Nginx
|
||||
# Для каждого сайта надо настроить свйо поток, со своим уникальным именем.
|
||||
# Если будете настраивать несколько python (django) сайтов - измените название upstream
|
||||
|
||||
upstream oknardia-django {
|
||||
# расположение файла Unix-сокет для взаимодействие с uwsgi
|
||||
server unix:/home/web/oknardia-ru/socket/oknardia.sock;
|
||||
# server ///home/web/oknardia-ru/socket/oknardia.sock;
|
||||
# также можно использовать веб-сокет (порт) для взаимодействие с uwsgi. Но это медленнее
|
||||
# server 127.0.0.1:8001; # для взаимодействия с uwsgi через веб-порт
|
||||
keepalive_requests 200;
|
||||
}
|
||||
|
||||
# конфигурируем сервер
|
||||
server {
|
||||
server_name tmp.cube2.ru; # доменное имя сайта
|
||||
listen 80; # managed by Certbot
|
||||
## listen 443 ssl http2; # managed by Certbot
|
||||
## ssl_certificate /etc/letsencrypt/live/cadpoint.ru/fullchain.pem; # managed by Certbot
|
||||
## ssl_certificate_key /etc/letsencrypt/live/cadpoint.ru/privkey.pem; # managed by Certbot
|
||||
## include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
|
||||
## ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
|
||||
|
||||
# server_name 90.156.203.25; # доменное имя сайта
|
||||
charset utf-8; # кодировка по умолчанию
|
||||
access_log /home/web/oknardia-ru/logs/oknardia-access.log; # логи с доступом
|
||||
error_log /home/web/oknardia-ru/logs/oknardia-error.log; # логи с ошибками
|
||||
client_max_body_size 100M; # максимальный объем файла для загрузки на сайт (max upload size)
|
||||
error_page 404 /404.html;
|
||||
error_page 500 /500.html;
|
||||
|
||||
location /media { alias /home/web/oknardia-ru/public/media; } # Расположение media-файлов Django
|
||||
location /static { alias /home/web/oknardia-ru/public/static; } # Расположение static-файлов Django
|
||||
|
||||
location /robots.txt { root /home/web/oknardia-ru/public; } # Расположение robots.txt
|
||||
location /favicon.ico { root /home/web/oknardia-ru/public; } # Расположение favicon.ico
|
||||
location /favicon.gif { root /home/web/oknardia-ru/public; } # Расположение favicon
|
||||
location /favicon.png { root /home/web/oknardia-ru/public; } # Расположение favicon
|
||||
location /favicon.svg { root /home/web/oknardia-ru/public; } # Расположение favicon
|
||||
location /author.txt { root /home/web/oknardia-ru/public; } # Расположение author.txt
|
||||
location = /404.html {
|
||||
root /home/web/oknardia-ru/oknardia/templates/404.html;
|
||||
internal;
|
||||
}
|
||||
location = /500.html {
|
||||
root /home/web/oknardia-ru/oknardia/templates/500.html;
|
||||
internal;
|
||||
}
|
||||
# location ~ \.(html|htm|ico|svg|png|gif|jpg|jpeg)$ {
|
||||
location ~ \.(xml|html|htm|ico|svg|png|gif|jpg|jpeg)$ {
|
||||
root /home/web/oknardia-ru/public; # Расположение статичных *.xml, *.html и *.txt
|
||||
}
|
||||
|
||||
location / {
|
||||
uwsgi_pass oknardia-django; # upstream обрабатывающий обращений
|
||||
include uwsgi_params; # конфигурационный файл uwsgi;
|
||||
proxy_set_header Host $host;
|
||||
|
||||
# ограничение количества запросов c одного IP-адреса с помощью модуля Limit_Req_Module
|
||||
# limit_req zone=one burst=20 nodelay;
|
||||
# one — имя зоны настроеной в /etc/nginx/nginx.conf (для всех сайтов сервера) в блоке http {…}
|
||||
# burst — максимальный всплеск активности, можно регулировать до какого значения запросов
|
||||
# в секунду может быть всплеск запросов;
|
||||
# nodelay — незамедлительно, при достижении лимита подключений, выдавать код 503
|
||||
# (Service Unavailable) для этого IP
|
||||
|
||||
fastcgi_keep_conn on;
|
||||
uwsgi_read_timeout 1800; # некоторые запросы на Raspbery pi очень долго обрабатываются. Например, переиндексация.
|
||||
uwsgi_send_timeout 200; # на всякий случай время записи в сокет
|
||||
}
|
||||
}
|
||||
|
||||
# переадресация с www на "без" www
|
||||
server {
|
||||
server_name www.tmp.cube2.ru;
|
||||
listen 80;
|
||||
return 301 http://tmp.cube2.ru$request_uri;
|
||||
|
||||
## listen 443 ssl; # managed by Certbot
|
||||
## ssl_certificate /etc/letsencrypt/live/cadpoint.ru/fullchain.pem; # managed by Certbot
|
||||
## ssl_certificate_key /etc/letsencrypt/live/cadpoint.ru/privkey.pem; # managed by Certbot
|
||||
## include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
|
||||
## ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
|
||||
}
|
||||
|
||||
# переадресация с http на https
|
||||
##server {
|
||||
## if ($host = oknardia.ru) {
|
||||
## return 301 https://$host$request_uri;
|
||||
## } # managed by Certbot
|
||||
##
|
||||
## listen 80;
|
||||
## server_name cadpoint.ru;
|
||||
## return 404; # managed by Certbot
|
||||
##}
|
||||
|
||||
# переадресация с http на https для www
|
||||
##server {
|
||||
## if ($host = www.cadpoint.ru) {
|
||||
## return 301 https://cadpoint.ru$request_uri;
|
||||
## } # managed by Certbot
|
||||
##
|
||||
## listen 80;
|
||||
## server_name www.cadpoint.ru;
|
||||
## return 404; # managed by Certbot
|
||||
##}
|
||||
|
||||
@@ -344,15 +344,25 @@ if DEBUG:
|
||||
pass
|
||||
|
||||
else:
|
||||
# В prod: WhiteNoise + CompressedManifestStaticFilesStorage для оптимизации.
|
||||
# В prod: WhiteNoise + CompressedStaticFilesStorage для оптимизации.
|
||||
# Статика собирается с хешем в имени и кэшируется.
|
||||
#
|
||||
# ВАЖНО: Для production нужна полная настройка Nginx:
|
||||
# - Nginx обслуживает статику (/static/) прямо из /home/app/public/static_collected/
|
||||
# - Nginx обслуживает медиа (/media/) прямо из /home/app/public/media/
|
||||
# - Nginx проксирует остальное на Gunicorn (:8000)
|
||||
#
|
||||
# Для локального тестирования production конфига этот файл симулирует Nginx.
|
||||
|
||||
# 1. Добавляем WhiteNoise в начало MIDDLEWARE (после SecurityMiddleware) для отдачи статики
|
||||
MIDDLEWARE.insert(1, 'whitenoise.middleware.WhiteNoiseMiddleware')
|
||||
|
||||
# 2. Переводим staticfiles на WhiteNoise со сжатием
|
||||
# ВАЖНО: используем CompressedStaticFilesStorage вместо CompressedManifestStaticFilesStorage,
|
||||
# потому что Manifest не справляется с relative paths в CSS (например, jQuery UI).
|
||||
# CompressedStaticFilesStorage сжимает файлы без manifest, что работает надежнее.
|
||||
STORAGES['staticfiles'] = {
|
||||
'BACKEND': 'whitenoise.storage.CompressedManifestStaticFilesStorage', # noqa: F821
|
||||
'BACKEND': 'whitenoise.storage.CompressedStaticFilesStorage', # noqa: F821
|
||||
}
|
||||
|
||||
# 3. WhiteNoise конфиг: обслуживание корневых файлов из public/ (robots.txt, favicon.*, sitemap.xml и т.д.)
|
||||
@@ -364,7 +374,21 @@ else:
|
||||
'.woff': 'font/woff',
|
||||
'.woff2': 'font/woff2',
|
||||
}
|
||||
# 5. Конфигурация WhiteNoise для обслуживания статических файлов и файлов из /public (например,
|
||||
# robots.txt, favicon.ico и т.п.)
|
||||
# WHITENOISE_ROOT = PUBLIC_ROOT
|
||||
|
||||
# 6. Кэширование неизменяемых файлов (с хешем в имени) на 1 год в браузере
|
||||
# ВАЖНО: лямбда должна принимает ДВА аргумента: path и url (как требует WhiteNoise)
|
||||
WHITENOISE_IMMUTABLE_FILE_TEST = lambda path, url: 'CACHE' in path
|
||||
|
||||
# 7. ЛОКАЛЬНЫЙ ТЕСТ: для отдачи медиа в docker-compose.local-prod.yml
|
||||
# В реальном production это обслуживает Nginx! Никогда не используй в production!
|
||||
# Добавляем StaticFilesHandler который обслуживает и медиа и статику
|
||||
if env.bool('ALLOW_MEDIA_SERVE', default=False):
|
||||
# Для локального тестирования добавляем обслуживание медиа через Django
|
||||
# ВАЖНО: это очень медленно и небезопасно для production!
|
||||
from django.conf.urls.static import static
|
||||
# Будет добавлено в urls.py при импорте: urlpatterns += static(MEDIA_URL, document_root=MEDIA_ROOT)
|
||||
|
||||
# 5. Кэширование неизменяемых файлов (с хешем в имени) на 1 год в браузере
|
||||
WHITENOISE_IMMUTABLE_FILE_TEST = lambda path: 'CACHE' in path
|
||||
|
||||
|
||||
@@ -17,6 +17,12 @@
|
||||
from django.contrib import admin
|
||||
from django.urls import include, path, re_path
|
||||
from django.conf.urls.static import static
|
||||
from pathlib import Path
|
||||
import environ
|
||||
# Инициализируем env
|
||||
env = environ.Env()
|
||||
PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent
|
||||
environ.Env.read_env(str(PROJECT_ROOT / '.env'))
|
||||
from oknardia.settings import *
|
||||
from web import views, autocomplete_addr, user_manager, blog, diagrams, report1, report2, catalog, prices, service, \
|
||||
catalog_profiles, catalog_series, catalog_openings, catalog_companies
|
||||
@@ -105,9 +111,24 @@ urlpatterns = [
|
||||
]
|
||||
|
||||
|
||||
# Для локального тестирования production конфига: отдача медиа через Django
|
||||
# В реальном production медиа обслуживает Nginx!
|
||||
import os
|
||||
if DEBUG or env.bool('ALLOW_MEDIA_SERVE', default=False):
|
||||
from django.views.static import serve as serve_static
|
||||
# Проверяем что директория медиа существует
|
||||
if os.path.isdir(MEDIA_ROOT):
|
||||
# Добавляем URL pattern для отдачи медиа файлов
|
||||
urlpatterns += [
|
||||
re_path(
|
||||
r'^media/(?P<path>.*)$',
|
||||
serve_static,
|
||||
{'document_root': MEDIA_ROOT},
|
||||
name='media'
|
||||
),
|
||||
]
|
||||
|
||||
if DEBUG:
|
||||
# Медиа-файлы
|
||||
urlpatterns += static(MEDIA_URL, document_root=MEDIA_ROOT)
|
||||
# --- страничка для тестирования верстки текста в блоге
|
||||
urlpatterns += [re_path(r'^blog/tmp[/*]$', service.tmp),]
|
||||
# ___ ____ _ _____ _ _ _____ _
|
||||
|
||||
Reference in New Issue
Block a user