From 35a3a9b0f96ed222bbd50c8cfd0f2f594acf3544 Mon Sep 17 00:00:00 2001 From: Bossanyi Tibor Date: Sat, 18 Jul 2020 17:29:32 +0200 Subject: [PATCH] production settings + menu tree implementation --- aitrainer_backoffice/__init__.py | 0 .../aitrainer_backoffice/admin.py | 42 ++++- .../aitrainer_backoffice/models.py | 51 ++++-- .../aitrainer_backoffice/settings/__init__.py | 1 + .../{settings.py => settings/dev.py} | 16 +- .../aitrainer_backoffice/settings/prod.py | 168 ++++++++++++++++++ .../aitrainer_backoffice/wsgi.py | 3 +- 7 files changed, 255 insertions(+), 26 deletions(-) create mode 100644 aitrainer_backoffice/__init__.py create mode 100644 aitrainer_backoffice/aitrainer_backoffice/settings/__init__.py rename aitrainer_backoffice/aitrainer_backoffice/{settings.py => settings/dev.py} (95%) create mode 100644 aitrainer_backoffice/aitrainer_backoffice/settings/prod.py diff --git a/aitrainer_backoffice/__init__.py b/aitrainer_backoffice/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/aitrainer_backoffice/aitrainer_backoffice/admin.py b/aitrainer_backoffice/aitrainer_backoffice/admin.py index fd3f9cf..c096131 100644 --- a/aitrainer_backoffice/aitrainer_backoffice/admin.py +++ b/aitrainer_backoffice/aitrainer_backoffice/admin.py @@ -4,6 +4,8 @@ from django.utils.translation import ugettext_lazy as _ from .models import ExerciseType from .models import ExerciseTypeImage from .models import ExerciseTypeTranslation +from .models import ExerciseTreeTranslation +from .models import ExerciseTree class ImageInline(admin.StackedInline): @@ -28,7 +30,7 @@ class TranslationInline(admin.TabularInline): class ExerciseTypeAdmin(admin.ModelAdmin): - list_display = ('exercise_type_id', 'name_colored', 'active') + list_display = ('name_colored', 'active') search_fields = ['name'] def name_colored(self, obj): @@ -48,4 +50,42 @@ class ExerciseTypeAdmin(admin.ModelAdmin): ] +class TranslationTreeInline(admin.TabularInline): + model = ExerciseTreeTranslation + fields = ('language_code', 'name',) + extra = 0 + + +class ExerciseTreeAdmin(admin.ModelAdmin): + list_display = ('name_colored', 'active') + search_fields = ['name'] + + fields = ["name", "parent_id", "image_url", "active", "get_image_preview"] + readonly_fields = ("get_image_preview",) + + def get_image_preview(self, obj): + image_url = '/media/' + str(obj.image_url) + if obj.pk: + return format_html(' ' \ + .format(url=image_url)) + + get_image_preview.short_description = _("Image Preview") + + def name_colored(self, obj): + if obj.active: + color_code = '7bc863' + else: + color_code = 'C20000' + html = '{}˓→'.format(color_code, obj.name) + return format_html(html) + + name_colored.admin_order_field = 'name' + name_colored.short_description = 'name' + + inlines = [ + TranslationTreeInline + ] + + admin.site.register(ExerciseType, ExerciseTypeAdmin) +admin.site.register(ExerciseTree, ExerciseTreeAdmin) diff --git a/aitrainer_backoffice/aitrainer_backoffice/models.py b/aitrainer_backoffice/aitrainer_backoffice/models.py index d836216..39f7c39 100644 --- a/aitrainer_backoffice/aitrainer_backoffice/models.py +++ b/aitrainer_backoffice/aitrainer_backoffice/models.py @@ -8,7 +8,7 @@ class ExerciseType(models.Model): SECOND = 'second' MINUTE = 'minute' METER = 'meter' - CM= 'centimeter' + CM = 'centimeter' PERCENT = 'percent' CALORIES = 'calories' KG = 'kilogram' @@ -19,7 +19,8 @@ class ExerciseType(models.Model): 'English here') unit = models.CharField(choices=UnitTypes.choices, default=UnitTypes.REPEAT, max_length=50, blank=True, null=True) unit_quantity = models.BooleanField(default=0, blank=True, null=True) - unit_quantity_unit = models.CharField(choices=UnitTypes.choices, default=UnitTypes.KG, max_length=50, blank=True, null=True) + unit_quantity_unit = models.CharField(choices=UnitTypes.choices, default=UnitTypes.KG, max_length=50, blank=True, + null=True) active = models.BooleanField(default=0, blank=True, null=True) class Meta: @@ -51,20 +52,13 @@ class ExerciseTypeImage(models.Model): def __str__(self): return self.name -''' - def image_tag(self): - from django.utils.html import escape - return u'' % escape(self.obj.url) - image_tag.short_description = 'Image' - image_tag.allow_tags = True -''' + +class LanguageTypes(models.TextChoices): + EN = "en" + HU = "hu" class ExerciseTypeTranslation(models.Model): - class LanguageTypes(models.TextChoices): - EN = "en" - HU = "hu" - translation_id = models.AutoField(primary_key=True) exercise_type = models.ForeignKey(ExerciseType, on_delete=models.CASCADE) language_code = models.CharField(max_length=2, choices=LanguageTypes.choices, default=LanguageTypes.HU) @@ -78,3 +72,34 @@ class ExerciseTypeTranslation(models.Model): def __str__(self): return self.name + + +class ExerciseTree(models.Model): + item_id = models.AutoField(primary_key=True) + parent_id = models.IntegerField(help_text='This is the parent menu ID. 0 if it is on the top of the tree') + name = models.CharField(max_length=100, help_text='The name should be in English here') + image_url = models.ImageField(upload_to='images/', help_text='The menu image size is 1366x768') + active = models.BooleanField(default=0, blank=True, null=True) + + class Meta: + db_table = 'exercise_tree' + verbose_name = _("Exercise Tree") + verbose_name_plural = _("Exercise Tree Items") + + def __str__(self): + return self.name + + +class ExerciseTreeTranslation(models.Model): + translation_id = models.AutoField(primary_key=True) + tree = models.ForeignKey(ExerciseTree, on_delete=models.CASCADE) + language_code = models.CharField(max_length=2, choices=LanguageTypes.choices, default=LanguageTypes.HU) + name = models.CharField(max_length=100) + + class Meta: + db_table = 'exercise_tree_translation' + verbose_name = _("Translation") + verbose_name_plural = _("Translations") + + def __str__(self): + return self.name diff --git a/aitrainer_backoffice/aitrainer_backoffice/settings/__init__.py b/aitrainer_backoffice/aitrainer_backoffice/settings/__init__.py new file mode 100644 index 0000000..c787328 --- /dev/null +++ b/aitrainer_backoffice/aitrainer_backoffice/settings/__init__.py @@ -0,0 +1 @@ +from .dev import * diff --git a/aitrainer_backoffice/aitrainer_backoffice/settings.py b/aitrainer_backoffice/aitrainer_backoffice/settings/dev.py similarity index 95% rename from aitrainer_backoffice/aitrainer_backoffice/settings.py rename to aitrainer_backoffice/aitrainer_backoffice/settings/dev.py index ba1220a..9ac12dc 100644 --- a/aitrainer_backoffice/aitrainer_backoffice/settings.py +++ b/aitrainer_backoffice/aitrainer_backoffice/settings/dev.py @@ -1,5 +1,5 @@ """ -Django settings for aitrainer_backoffice project. +Django settings for aitrainer_backoffice project. (development) Generated by 'django-admin startproject' using Django 3.0.8. @@ -15,18 +15,16 @@ import os # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'fic(oo70m2itz&6-=!)j)$g+p8(s#aud7u7tpaqxd&2562grb@' +SECRET_KEY = os.environ['DJANGO_KEY'] # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = [] - +ALLOWED_HOSTS = ['localhost'] # Application definition @@ -70,7 +68,6 @@ TEMPLATES = [ WSGI_APPLICATION = 'aitrainer_backoffice.wsgi.application' - # Database # https://docs.djangoproject.com/en/3.0/ref/settings/#databases @@ -79,13 +76,12 @@ DATABASES = { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'aitrainer2', 'USER': 'aitrainer', - 'PASSWORD':'andio2009', + 'PASSWORD': 'andio2009', 'HOST': '127.0.0.1', - 'PORT':3306 + 'PORT': 3306 } } - # Password validation # https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators @@ -104,7 +100,6 @@ AUTH_PASSWORD_VALIDATORS = [ }, ] - # Internationalization # https://docs.djangoproject.com/en/3.0/topics/i18n/ @@ -118,7 +113,6 @@ USE_L10N = True USE_TZ = True - # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.0/howto/static-files/ diff --git a/aitrainer_backoffice/aitrainer_backoffice/settings/prod.py b/aitrainer_backoffice/aitrainer_backoffice/settings/prod.py new file mode 100644 index 0000000..ee40c82 --- /dev/null +++ b/aitrainer_backoffice/aitrainer_backoffice/settings/prod.py @@ -0,0 +1,168 @@ +""" +Django settings for aitrainer_backoffice project. + +Generated by 'django-admin startproject' using Django 3.0.8. + +For more information on this file, see +https://docs.djangoproject.com/en/3.0/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/3.0/ref/settings/ +""" + +import os + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = os.environ['DJANGO_KEY'] + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = False + +ALLOWED_HOSTS = ['localhost', 'andio.eu', 'aitrainer.*'] + +# Application definition + +INSTALLED_APPS = [ + 'aitrainer_backoffice.apps.BackofficeConfig', + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', +] + +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 = 'aitrainer_backoffice.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + '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', + ], + }, + }, +] + +WSGI_APPLICATION = 'aitrainer_backoffice.wsgi.application' + +# Database +# https://docs.djangoproject.com/en/3.0/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': 'aitrainer2', + 'USER': 'aitrainer', + 'PASSWORD': 'andio2009', + 'HOST': '127.0.0.1', + 'PORT': 3306 + } +} + +# Password validation +# https://docs.djangoproject.com/en/3.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/3.0/topics/i18n/ + +LANGUAGE_CODE = 'hu-HU' + +TIME_ZONE = 'Europe/Budapest' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/3.0/howto/static-files/ + +STATIC_URL = '/static/' + +MEDIA_URL = '/media/' +MEDIA_ROOT = os.path.join(BASE_DIR, 'media') + +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'filters': { + 'require_debug_true': { + '()': 'django.utils.log.RequireDebugTrue', + }, + }, + 'handlers': { + 'console': { + 'class': 'logging.StreamHandler', + 'filters': ['require_debug_true'], + }, + }, + 'loggers': { + 'mylogger': { + 'handlers': { + 'file': { + 'level': 'ERROR', + 'class': 'logging.FileHandler', + 'filename': '/var/log/django_error.log', + }, + }, + 'level': os.getenv('DJANGO_LOG_LEVEL', 'ERROR'), + 'propagate': True, + }, + }, +} + +# deployment settings +SECURE_SSL_REDIRECT = False +SESSION_COOKIE_SECURE = True +CSRF_COOKIE_SECURE = True + +CACHES = { + 'default': { + 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', + 'LOCATION': '/var/tmp/django_cache', + 'TIMEOUT': 300, + 'OPTIONS': { + 'MAX_ENTRIES': 50000 + } + } +} + diff --git a/aitrainer_backoffice/aitrainer_backoffice/wsgi.py b/aitrainer_backoffice/aitrainer_backoffice/wsgi.py index 3992646..1a08b7b 100644 --- a/aitrainer_backoffice/aitrainer_backoffice/wsgi.py +++ b/aitrainer_backoffice/aitrainer_backoffice/wsgi.py @@ -11,6 +11,7 @@ import os from django.core.wsgi import get_wsgi_application -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'aitrainer_backoffice.settings') +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'aitrainer_backoffice.settings.prod') application = get_wsgi_application() +