PyInventory/src/inventory_project/settings/base.py

382 wiersze
12 KiB
Python

'''
Base Django settings
'''
import logging
from pathlib import Path as __Path
from ckeditor.configs import DEFAULT_CONFIG
from django.utils.translation import gettext_lazy as _
###############################################################################
# Build paths relative to the project root:
PROJECT_PATH = __Path(__file__).parent.parent.parent
print(f'PROJECT_PATH:{PROJECT_PATH}')
if __Path('/.dockerenv').is_file():
# We are inside a docker container
BASE_PATH = __Path('/django_volumes')
assert BASE_PATH.is_dir()
else:
# Build paths relative to the current working directory:
BASE_PATH = __Path().cwd().resolve()
print(f'BASE_PATH:{BASE_PATH}')
# Paths with Django dev. server:
# BASE_PATH...: .../django-for-runners
# PROJECT_PATH: .../django-for-runners/src
#
# Paths in Docker container:
# BASE_PATH...: /for_runners_volumes
# PROJECT_PATH: /usr/local/lib/python3.9/site-packages
###############################################################################
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False
# Serve static/media files by Django?
# In production Caddy should serve this!
SERVE_FILES = False
# SECURITY WARNING: keep the secret key used in production secret!
__SECRET_FILE = __Path(BASE_PATH, 'secret.txt').resolve()
if not __SECRET_FILE.is_file():
print(f'Generate {__SECRET_FILE}')
from secrets import token_urlsafe as __token_urlsafe
__SECRET_FILE.open('w').write(__token_urlsafe(128))
SECRET_KEY = __SECRET_FILE.open('r').read().strip()
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites',
'bx_django_utils', # https://github.com/boxine/bx_django_utils
'import_export', # https://github.com/django-import-export/django-import-export
'dbbackup', # https://github.com/django-dbbackup/django-dbbackup
'ckeditor', # https://github.com/django-ckeditor/django-ckeditor
'ckeditor_uploader', # https://github.com/django-ckeditor/django-ckeditor
'reversion', # https://github.com/etianen/django-reversion
'reversion_compare', # https://github.com/jedie/django-reversion-compare
'tagulous', # https://github.com/radiac/django-tagulous
'adminsortable2', # https://github.com/jrief/django-admin-sortable2
'axes', # https://github.com/jazzband/django-axes
'django_processinfo', # https://github.com/jedie/django-processinfo/
# https://github.com/jedie/django-tools/tree/master/django_tools/serve_media_app
'django_tools.serve_media_app.apps.UserMediaFilesConfig',
# https://github.com/jedie/django-tools/tree/master/django_tools/model_version_protect
'django_tools.model_version_protect.apps.ModelVersionProtectConfig',
'inventory.apps.InventoryConfig',
]
ROOT_URLCONF = 'inventory_project.urls'
WSGI_APPLICATION = 'inventory_project.wsgi.application'
SITE_ID = 1
AUTHENTICATION_BACKENDS = [
'axes.backends.AxesBackend',
'django.contrib.auth.backends.ModelBackend',
]
MIDDLEWARE = [
'django_processinfo.middlewares.ProcessInfoMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'inventory.middlewares.RequestDictMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.security.SecurityMiddleware',
'axes.middleware.AxesMiddleware', # AxesMiddleware should be the last middleware
]
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [str(__Path(PROJECT_PATH, 'inventory_project', 'templates'))],
'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',
'inventory.context_processors.inventory_version_string',
],
},
},
]
# _____________________________________________________________________________
# Internationalization
LANGUAGE_CODE = 'en'
LANGUAGES = [
('ca', _('Catalan')),
('de', _('German')),
('en', _('English')),
('es', _('Spanish'))
]
USE_I18N = True
USE_L10N = True
TIME_ZONE = 'Europe/Paris'
USE_TZ = True
# _____________________________________________________________________________
# Static files (CSS, JavaScript, Images)
STATIC_URL = '/static/'
STATIC_ROOT = str(__Path(BASE_PATH, 'static'))
MEDIA_URL = '/media/'
MEDIA_ROOT = str(__Path(BASE_PATH, 'media'))
# _____________________________________________________________________________
# django-processinfo
from django_processinfo import app_settings as PROCESSINFO # noqa
PROCESSINFO.ADD_INFO = False # Don't add info in HTML page
# _____________________________________________________________________________
# Django-dbbackup
DBBACKUP_STORAGE = 'django.core.files.storage.FileSystemStorage'
DBBACKUP_STORAGE_OPTIONS = {'location': str(__Path(BASE_PATH, 'backups'))}
# _____________________________________________________________________________
# django-ckeditor
CKEDITOR_BASEPATH = STATIC_URL + 'ckeditor/ckeditor/'
CKEDITOR_FILENAME_GENERATOR = 'inventory.ckeditor_upload.get_filename'
CKEDITOR_DEFAULT_CONFIG = DEFAULT_CONFIG
CKEDITOR_DEFAULT_CONFIG.update({
'removeButtons': 'Language,Cut,Copy,Paste,Undo,Redo,Anchor',
# plugins are here: .../site-packages/ckeditor/static/ckeditor/ckeditor/plugins
# and here: https://github.com/ckeditor/ckeditor4/tree/major/plugins
# See also: .../site-packages/ckeditor/static/ckeditor/ckeditor/build-config.js
'removePlugins': (
# Generated with devshell command:
# (inventory) ckeditor_info
'a11yhelp',
# 'about',
'adobeair',
'ajax',
'autoembed',
# 'autogrow',
'autolink',
# 'basicstyles',
'bbcode',
'bidi',
# 'blockquote',
'clipboard',
'codesnippet',
'codesnippetgeshi',
# 'colorbutton',
# 'colordialog',
'contextmenu',
'copyformatting',
'devtools',
'dialog',
'dialogadvtab',
'div',
'divarea',
'docprops',
# 'elementspath',
'embed',
'embedbase',
'embedsemantic',
'enterkey',
# 'entities',
'exportpdf',
# 'filebrowser',
# 'filetools',
'find',
'flash',
# 'floatingspace',
# 'font',
# 'format',
'forms',
# 'horizontalrule',
'htmlwriter',
'iframe',
'iframedialog',
# 'image',
# 'image2',
# 'indentblock',
# 'indentlist',
# 'justify',
'language',
# 'lineutils',
# 'link',
# 'list',
# 'liststyle',
'magicline',
'mathjax',
# 'maximize',
# 'menubutton',
'newpage',
'notification',
'notificationaggregator',
'pagebreak',
'pastefromgdocs',
'pastefromword',
'pastetext',
'pastetools',
'placeholder',
'preview',
'print',
# 'removeformat',
# 'resize',
'save',
'scayt',
'selectall',
'sharedspace',
# 'showblocks',
# 'showborders',
'smiley',
# 'sourcearea',
'sourcedialog',
'specialchar',
'stylescombo',
'stylesheetparser',
'tab',
# 'table',
# 'tableresize',
# 'tableselection',
# 'tabletools',
'templates',
# 'toolbar',
'uicolor',
# 'undo',
# 'uploadimage',
# 'uploadwidget',
'widget',
'wsc',
# 'wysiwygarea',
'xml',
),
'toolbar_PyInventoryToolbarConfig': [
{'name': 'basicstyles', 'items': [
'Bold', 'Italic', 'Underline', 'Strike',
'-',
'RemoveFormat'
]},
{'name': 'paragraph', 'items': [
'NumberedList', 'BulletedList',
'-',
'Outdent', 'Indent',
'-',
'Blockquote',
'-',
'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock',
]},
{'name': 'links', 'items': ['Link', 'Unlink', 'Anchor']},
{'name': 'insert', 'items': ['Image', 'Table', 'HorizontalRule']},
'/',
{'name': 'styles', 'items': ['Styles', 'Format', 'Font', 'FontSize']},
{'name': 'colors', 'items': ['TextColor', 'BGColor']},
{'name': 'tools', 'items': ['Maximize', 'ShowBlocks', 'Source']},
{'name': 'about', 'items': ['About']},
],
'toolbar': 'PyInventoryToolbarConfig',
'height': '25em',
'width': '100%',
})
CKEDITOR_CONFIGS = {
'ItemModel.description': CKEDITOR_DEFAULT_CONFIG,
'LocationModel.description': CKEDITOR_DEFAULT_CONFIG,
'MemoModel.description': CKEDITOR_DEFAULT_CONFIG,
}
CKEDITOR_RESTRICT_BY_USER = True
CKEDITOR_RESTRICT_BY_DATE = True
CKEDITOR_UPLOAD_PATH = 'uploads/'
CKEDITOR_IMAGE_BACKEND = 'pillow'
CKEDITOR_THUMBNAIL_SIZE = (300, 300)
CKEDITOR_IMAGE_QUALITY = 40
CKEDITOR_BROWSE_SHOW_DIRS = True
CKEDITOR_ALLOW_NONIMAGE_FILES = True
# _____________________________________________________________________________
# http://radiac.net/projects/django-tagulous/documentation/installation/#settings
TAGULOUS_NAME_MAX_LENGTH = 255
TAGULOUS_SLUG_MAX_LENGTH = 50
TAGULOUS_LABEL_MAX_LENGTH = TAGULOUS_NAME_MAX_LENGTH
TAGULOUS_SLUG_TRUNCATE_UNIQUE = 5
TAGULOUS_SLUG_ALLOW_UNICODE = False
SERIALIZATION_MODULES = {
'xml': 'tagulous.serializers.xml_serializer',
'json': 'tagulous.serializers.json',
'python': 'tagulous.serializers.python',
'yaml': 'tagulous.serializers.pyyaml',
}
# _____________________________________________________________________________
# cut 'pathname' in log output
old_factory = logging.getLogRecordFactory()
def cut_path(pathname, max_length):
if len(pathname) <= max_length:
return pathname
return f'...{pathname[-(max_length - 3):]}'
def record_factory(*args, **kwargs):
record = old_factory(*args, **kwargs)
record.cut_path = cut_path(record.pathname, 30)
return record
logging.setLogRecordFactory(record_factory)
# -----------------------------------------------------------------------------
LOGGING = {
'version': 1,
'disable_existing_loggers': True,
'formatters': {
'colored': { # https://github.com/borntyping/python-colorlog
'()': 'colorlog.ColoredFormatter',
'format': '%(log_color)s%(asctime)s %(levelname)8s %(cut_path)s:%(lineno)-3s %(message)s',
}
},
'handlers': {'console': {'class': 'colorlog.StreamHandler', 'formatter': 'colored'}},
'loggers': {
'': {'handlers': ['console'], 'level': 'DEBUG', 'propagate': False},
'django': {'handlers': ['console'], 'level': 'INFO', 'propagate': False},
'axes': {'handlers': ['console'], 'level': 'WARNING', 'propagate': False},
'django_tools': {'handlers': ['console'], 'level': 'INFO', 'propagate': False},
'inventory': {'handlers': ['console'], 'level': 'DEBUG', 'propagate': False},
},
}