Files
2018-lpon-site/lpon_site/lpon_site/settings.py

334 lines
13 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Django settings for lpon_site project.
Generated by 'django-admin startproject' using Django 6.0.5.
For more information on this file, see
https://docs.djangoproject.com/en/6.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/6.0/ref/settings/
"""
from pathlib import Path
import environ
import os
from enum import IntEnum
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Читаем переменные окружения
env = environ.Env()
environ.Env.read_env(os.path.join(BASE_DIR.parent, '.env'))
def _normalize_admin_url(value: str) -> str:
"""Приводит URL админки к виду `segment/` без ведущего слэша."""
normalized = value.strip().lstrip('/')
if not normalized:
return 'admin/'
if not normalized.endswith('/'):
normalized += '/'
return normalized
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = env('DJANGO_SECRET_KEY', default='3xym$l+!)erah-k23lf0=t=c_4$e0nr*zls&l%pbz@k6v6qn89')
ADMIN_URL = _normalize_admin_url(env('DJANGO_ADMIN_URL', default='admin/'))
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = env.bool('DJANGO_DEBUG', default=False)
ALLOWED_HOSTS = env.list(
'DJANGO_ALLOWED_HOSTS',
default=['127.0.0.1', 'localhost', 'testserver', 'lpon.ru'],
)
CSRF_TRUSTED_ORIGINS = env.list('DJANGO_CSRF_TRUSTED_ORIGINS', default=['127.0.0.1', 'localhost', 'testserver'])
#########################################
# Настройки сообщений об ошибках когда все упало и т.п.
ADMINS = tuple(
tuple(item.split(':', 1))
for item in env.list('DJANGO_ADMINS', default=['S.Erjemin:erjemin@gmail.com'])
)
# Application definition
INSTALLED_APPS = [
# Django core
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# Django-filer и его зависимости
# Порядок важен! polymorphic должен быть ДО filer, easy_thumbnails тоже ДО filer
# 'polymorphic',
'easy_thumbnails',
# 'filer',
# Кастомная надстройка над filer для переопределения verbose_name (и других настроек)
'frontend.apps.CustomFilerConfig',
# Наше приложение
'frontend.apps.FrontendConfig',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'lpon_site.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'lpon_site.wsgi.application'
# Database
# https://docs.djangoproject.com/en/6.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR.parent.joinpath('database', env('DJANGO_SQLITE_NAME', default='lpon-db.sqlite3')),
'CONN_MAX_AGE': 600, # время жизни соединения с базой
'OPTIONS': {
'timeout': 25,
'init_command': "PRAGMA journal_mode=WAL; PRAGMA auto_vacuum=2;",
},
}
}
# Password validation
# https://docs.djangoproject.com/en/6.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/6.0/topics/i18n/
LANGUAGE_CODE = 'ru-RU' #
# TIME_ZONE = 'Etc/GMT+3' #
TIME_ZONE = 'Europe/Moscow' #
USE_I18N = True
USE_TZ = True
FIRST_DAY_OF_WEEK = 1 # неделя начинается с понедельника
DEFAULT_CHARSET = 'utf-8'
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/6.0/howto/static-files/
STATIC_URL = '/static/'
MEDIA_URL = '/media/'
# Локальные каталоги проекта: медиа и статика лежат рядом в `public`.
PUBLIC_DIR = BASE_DIR.parent.joinpath('public') # Папка `public` находится в корне пректа
MEDIA_ROOT = PUBLIC_DIR.joinpath('media')
STATICFILES_DIRS = [PUBLIC_DIR.joinpath('static')]
STATIC_ROOT = PUBLIC_DIR.joinpath('staticfiles')
# ============================================================================
# Django-Filer & Easy-Thumbnails Configuration
# ============================================================================
# Примечание о потоках обработки:
# - Django: количество worker-процессов настраивается через gunicorn/uWSGI (--workers, --threads)
# - Pillow-HEIF: параллелизм настраивается через pillow_heif.options.DECODE_THREADS в apps.py
# - Easy-Thumbnails: использует Pillow напрямую, параллелизм через Pillow
# ============================================================================
FILER_STORAGES = {
'public': {
'main': {
'ENGINE': 'filer.storage.PublicFileSystemStorage',
'OPTIONS': {
'location': MEDIA_ROOT / 'flr',
'base_url': MEDIA_URL + 'flr/',
},
'UPLOAD_TO': 'filer.utils.generate_filename.randomized',
'UPLOAD_TO_PREFIX': '',
},
'thumbnails': {
'ENGINE': 'filer.storage.PublicFileSystemStorage',
'OPTIONS': {
'location': MEDIA_ROOT / 'flrm',
'base_url': MEDIA_URL + 'flrm/',
},
# Переопределяем THUMBNAIL_OPTIONS чтобы убрать prefix 'filer_public_thumbnails'
# По умолчанию filer добавляет 'base_dir': 'filer_public_thumbnails', мы это отключаем
# Почему-то этого нет в документации. :(
'THUMBNAIL_OPTIONS': {
'base_dir': '',
},
},
},
}
# Настройки easy_thumbnails для генерации миниатюр
# Преимущественно используется для django-filer
THUMBNAIL_PRESERVE_FORMAT = False
THUMBNAIL_FORMAT = 'WEBP'
THUMBNAIL_DEBUG = DEBUG
THUMBNAIL_QUALITY= 80
THUMBNAIL_WEBP_QUALITY = THUMBNAIL_QUALITY # Наша, кастомная настройка для WebP-сжатия исходных картинок
THUMBNAIL_ENGINE = 'easy_thumbnails.engines.pil_engine.PilEngine'
# Список расширений, которые нужно сохранять при генерации миниатюр
# Это важно для WebP файлов - они не должны быть сконвертированы в другой формат
THUMBNAIL_PRESERVE_EXTENSIONS = ['png', 'gif', 'webp']
# Нейминг миниатюр - стандартный нейминг easy_thumbnails
# Формат: {source_name}{dimensions}{options}{quality}{extra}
# Например: image.webp__40x40_q85_crop_subsampling-2.jpg
THUMBNAIL_NAMER = 'easy_thumbnails.namers.default'
# Показывать ошибки при генерации миниатюр (полезно для отладки)
THUMBNAIL_VERBOSE = DEBUG
THUMBNAIL_ALIASES = {
'': {
# Примечание: filer автоматически генерирует свои миниатюры для админки (40x40, 210x210 и 420x420)
# через DEFAULT_THUMBNAILS (см. BaseImage класс в filer).
'small': {'size': (256, 256), 'crop': True},
'medium': {'size': (512, 512), 'crop': True},
'large': {'size': (1024, 1024), 'crop': 'smart'},
},
}
FILER_UPLOADER_MAX_FILES = 3
FILER_UPLOADER_MAX_FILE_SIZE = 100 * 1024 * 1024
FILER_MAX_IMAGE_PIXELS = 4096 * 4096
FILER_ENABLE_PERMISSIONS = DEBUG
FILER_WHITELIST_FOR_PATH_ACCESS = (
'.jpg', '.jpeg', '.png', '.gif', '.svg', '.webp', '.heic', '.heif',
'.doc', '.docx', '.pdf', '.xls', '.xlsx', '.txt', '.csv',
)
MIME_TYPE_WHITELIST = (
'image/jpeg', # .jpg / .jpeg
'image/png', 'image/x-png', # .png
'image/gif',
'image/svg+xml',
'image/webp',
'image/heic', 'image/heif', # форматы Apple HEIC/HEIF (без анимации 'image/heic-sequence и 'image/heif-sequence')
'application/pdf',
'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', # .doc / .docx
'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', # .xls / .xlsx
'text/plain',
'text/csv',
)
FILE_VALIDATORS = {}
# Настройки для "умной" обрезки изображений
THUMBNAIL_PROCESSORS = (
'easy_thumbnails.processors.colorspace',
'easy_thumbnails.processors.autocrop',
# 'easy_thumbnails.processors.scale_and_crop',
'filer.thumbnail_processors.scale_and_crop_with_subject_location',
'easy_thumbnails.processors.filters',
)
# Конфигурация логирования для отладки загрузок и обработки файлов
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '[{levelname}] {asctime} {name}:{funcName}() line {lineno} - {message}',
'style': '{',
'datefmt': '%Y-%m-%d %H:%M:%S',
},
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'formatter': 'verbose',
},
'file': {
'class': 'logging.FileHandler',
'filename': os.path.join(BASE_DIR.parent, 'logs', 'uploads.log'),
'formatter': 'verbose',
},
},
'loggers': {
'frontend.apps': {
'level': 'DEBUG',
'handlers': ['console', 'file'],
'propagate': False,
},
'frontend.models': {
'level': 'DEBUG',
'handlers': ['console', 'file'],
'propagate': False,
},
'easy_thumbnails': {
'level': 'DEBUG',
'handlers': ['console', 'file'],
'propagate': False,
},
'filer': {
'level': 'DEBUG',
'handlers': ['console', 'file'],
'propagate': False,
},
},
}
# ===================================================
# СПЕЦИФИЧНЫЕ ДЛЯ ПРОЕКТА КОНСТАНТЫ И НАСТРОЙКИ
# Максимальная длина slug: Весь URL оптимально иметь до 70 символов (методичка Google, так как такой URL виден целиком
# на страничке поисковой выдачи, вызывает больше доверия и кликов). С учетом того, что
# в URL входит имя домена и slug-и разделов, оптимально устанавливать slug даже короче
# (20-30 символов максимум).
# SLUG_MAX_LENGTH задает ограничение для slug-ов созданных автоматически. Вручную в admin можно задать до 255 символов.
SLUG_MAX_LENGTH = 60
# Ключи для типовых параметров в мета-полях (для TbLabel, TbSeller, TbArtist, TbMusicStyle и т.д.)
KEY_SYNONYM = 'SYNONYM'
# ДЛЯ ВАЛИДАЦИИ (поиска похожих исполнителей, стилей и т.д. (используется в TbLabel.matching_type, TbSeller.matching_type и т.д.)
VALIDATE_KEY__MATCH_TYPE = 'MATCH_TYPE'
VALIDATE_KEY__MODEL = 'MODEL'
VALIDATE_KEY__VALUE = 'MATCH_VALUE'
# Типы совпадений как Enum (более информативно чем просто числа, работает в match-case)
class ValidateMatchType(IntEnum):
"""Типы совпадений при поиске дубликатов."""
IS_DUPLICATE = 1 # Точное совпадение основного поля (s_label, s_artist и т.д.)
FIND_IN_SYNONYM = 2 # Частичное совпадение
# SYNONYM_MATCH = 3 # Совпадение по синониму