diff --git a/BaseModels/admin_utils.py b/BaseModels/admin_utils.py index caea29d..dcdd965 100644 --- a/BaseModels/admin_utils.py +++ b/BaseModels/admin_utils.py @@ -84,6 +84,11 @@ def get_base_fieldsets(): return fieldsets +from django.forms import ModelForm, FileField + + + + class AdminImageWidget(AdminFileWidget): def render(self, name, value, attrs=None, renderer=None): @@ -94,6 +99,12 @@ class AdminImageWidget(AdminFileWidget): return mark_safe(u''.join(output)) +# отображение фото в админке +formfield_overrides_images = { + models.ImageField: {'widget': AdminImageWidget}, + models.FileField: {'widget': AdminImageWidget}, + } + def init_formfield_for_dbfield(class_model, self, db_field, request, **kwargs): formfield = super(class_model, self).formfield_for_dbfield(db_field, request, **kwargs) @@ -218,15 +229,15 @@ class Admin_GenericBaseIconStackedInline(GenericStackedInline): def image_thumb(self, obj): return get_image_thumb(self, obj) - formfield_overrides = { - models.ImageField: {'widget': AdminImageWidget}, - } + formfield_overrides = formfield_overrides_images image_thumb.short_description = u'Миниатюра' image_thumb.allow_tags = True + + class Admin_BaseIconStackedInline(admin.StackedInline): def formfield_for_dbfield (self, db_field, request, **kwargs): @@ -238,9 +249,7 @@ class Admin_BaseIconStackedInline(admin.StackedInline): image_thumb.short_description = u'Миниатюра' image_thumb.allow_tags = True - formfield_overrides = { - models.ImageField: {'widget': AdminImageWidget}, - } + formfield_overrides = formfield_overrides_images class Admin_BaseIconTabularModel(admin.TabularInline): @@ -272,9 +281,7 @@ class Admin_BaseIconModel(admin.ModelAdmin): def formfield_for_dbfield (self, db_field, request, **kwargs): return init_formfield_for_dbfield(Admin_BaseIconModel, self, db_field, request, **kwargs) - formfield_overrides = { - models.ImageField: {'widget': AdminImageWidget}, - } + formfield_overrides = formfield_overrides_images def image_thumb(self, obj): return get_image_thumb(self, obj) diff --git a/BaseModels/base_models.py b/BaseModels/base_models.py index 96039eb..2249fe1 100644 --- a/BaseModels/base_models.py +++ b/BaseModels/base_models.py @@ -17,7 +17,24 @@ from django.contrib.contenttypes.fields import GenericRelation # add_introspection_rules([], ["^tinymce\.models\.HTMLField"]) +from django.core.exceptions import ValidationError +import os + +def validate_file_extension(value): + ext = os.path.splitext(value.name)[1] # [0] returns path & filename + valid_extensions = ['.jpg', '.png', '.svg'] # populate with the extensions that you allow / want + if not ext.lower() in valid_extensions: + raise ValidationError('Unsupported file extension.') + + +class Manager_Enabled(models.Manager): + def get_queryset(self): + return super(Manager_Enabled, + self).get_queryset().filter(enable=True) + + class BaseModel(models.Model): + name = models.TextField(verbose_name=_('Название'), help_text=_('Название'), null=True, blank=True) name_plural = models.TextField(verbose_name=_('Название (множественное число)'), @@ -73,6 +90,9 @@ class BaseModel(models.Model): class Meta: abstract = True + objects = models.Manager() + enabled_objs = Manager_Enabled() + def preSave_BaseModel(sender, instance, **kwargs): if instance and instance.user_profile: @@ -91,8 +111,8 @@ class BaseModelViewPage(BaseModel): help_text=_('краткое описание страницы (до 240 символов)')) text = RichTextUploadingField(verbose_name=_('Полное описание'), null=True, blank=True, ) # help_text=_(u'краткое описание страницы (до 240 символов)')) - picture = models.ImageField(upload_to='uploads/', verbose_name=_('Картинка'), null=True, blank=True, - help_text=u'') + picture = models.FileField(upload_to='uploads/', verbose_name=_('Картинка'), null=True, blank=True, + validators=[validate_file_extension]) # icon = FileBrowseField("Image", max_length=200, directory="files/", extensions=[".jpg"], blank=True, null=True) visible = models.BooleanField(verbose_name=_('Отображать'), default=True) # background_image_left = models.ImageField(verbose_name=_('Левая подложка'), blank=True, null=True) @@ -110,10 +130,10 @@ class BaseModelViewPage(BaseModel): blocks = GenericRelation('GeneralApp.Block', related_query_name='grel_%(class)s_for_block_item') - class Meta: abstract = True + def get_description_exists(self): if self.description: return True diff --git a/GeneralApp/admin.py b/GeneralApp/admin.py index c999b89..5737e74 100644 --- a/GeneralApp/admin.py +++ b/GeneralApp/admin.py @@ -26,7 +26,7 @@ class Admin_Inline_WidgetForBlock(SuperInlineModelAdmin, Admin_Trans_BaseIconSta 'fields': [ ('title', 'description', 'picture'), ('bg_color', ), - ('but_title', 'but_color'), + ('but_title', 'but_color', 'but_icon'), ('url', 'order'), ] }) @@ -49,7 +49,7 @@ class Admin_StackedInline_Block(Admin_Trans_GenericBaseIconStackedInline, SuperI 'fields': [ ('block_type', 'title', 'description', 'picture'), ('bg_color', ), - ('but_title', 'but_color'), + ('but_title', 'but_color', 'but_icon'), ('url',), ('child_in_row_count', 'order'), ] diff --git a/GeneralApp/migrations/0008_alter_block_block_type.py b/GeneralApp/migrations/0008_alter_block_block_type.py new file mode 100644 index 0000000..37f2b6b --- /dev/null +++ b/GeneralApp/migrations/0008_alter_block_block_type.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.7 on 2023-11-27 16:25 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('GeneralApp', '0007_alter_widgetforblock_options_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='block', + name='block_type', + field=models.CharField(choices=[('photo_n_text', 'Фото + текст'), ('photo150_n_title', 'Фото 150x150 + заголовок'), ('how_work', 'Как с нами работать')], default='photo_n_text', max_length=100, verbose_name='Тип блока'), + ), + ] diff --git a/GeneralApp/migrations/0009_alter_block_picture_alter_staticpage_picture.py b/GeneralApp/migrations/0009_alter_block_picture_alter_staticpage_picture.py new file mode 100644 index 0000000..7a60097 --- /dev/null +++ b/GeneralApp/migrations/0009_alter_block_picture_alter_staticpage_picture.py @@ -0,0 +1,24 @@ +# Generated by Django 4.2.7 on 2023-11-27 17:13 + +import BaseModels.base_models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('GeneralApp', '0008_alter_block_block_type'), + ] + + operations = [ + migrations.AlterField( + model_name='block', + name='picture', + field=models.FileField(blank=True, null=True, upload_to='uploads/', validators=[BaseModels.base_models.validate_file_extension], verbose_name='Картинка'), + ), + migrations.AlterField( + model_name='staticpage', + name='picture', + field=models.FileField(blank=True, null=True, upload_to='uploads/', validators=[BaseModels.base_models.validate_file_extension], verbose_name='Картинка'), + ), + ] diff --git a/GeneralApp/migrations/0010_block_but_icon_widgetforblock_but_icon_and_more.py b/GeneralApp/migrations/0010_block_but_icon_widgetforblock_but_icon_and_more.py new file mode 100644 index 0000000..d8b130f --- /dev/null +++ b/GeneralApp/migrations/0010_block_but_icon_widgetforblock_but_icon_and_more.py @@ -0,0 +1,34 @@ +# Generated by Django 4.2.7 on 2023-11-27 17:28 + +import BaseModels.base_models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('GeneralApp', '0009_alter_block_picture_alter_staticpage_picture'), + ] + + operations = [ + migrations.AddField( + model_name='block', + name='but_icon', + field=models.FileField(blank=True, null=True, upload_to='uploads/', validators=[BaseModels.base_models.validate_file_extension], verbose_name='Пиктограмма для кнопки'), + ), + migrations.AddField( + model_name='widgetforblock', + name='but_icon', + field=models.FileField(blank=True, null=True, upload_to='uploads/', validators=[BaseModels.base_models.validate_file_extension], verbose_name='Пиктограмма для кнопки'), + ), + migrations.AlterField( + model_name='option', + name='picture', + field=models.FileField(blank=True, null=True, upload_to='uploads/', validators=[BaseModels.base_models.validate_file_extension], verbose_name='Миниатюра'), + ), + migrations.AlterField( + model_name='widgetforblock', + name='picture', + field=models.FileField(blank=True, null=True, upload_to='uploads/', validators=[BaseModels.base_models.validate_file_extension], verbose_name='Картинка'), + ), + ] diff --git a/GeneralApp/models.py b/GeneralApp/models.py index 91ff4e4..1944078 100644 --- a/GeneralApp/models.py +++ b/GeneralApp/models.py @@ -1,5 +1,5 @@ from django.db import models -from BaseModels.base_models import BaseModelViewPage, BaseModel +from BaseModels.base_models import BaseModelViewPage, BaseModel, validate_file_extension from django.utils.translation import gettext_lazy as _ # from ckeditor.fields import RichTextField from ckeditor_uploader.fields import RichTextUploadingField @@ -20,16 +20,27 @@ class StaticPage(BaseModelViewPage): block_type_choices = ( ('photo_n_text', _('Фото + текст')), ('photo150_n_title', _('Фото 150x150 + заголовок')), - ('slider', _('Галерея слайдов')), + ('how_work', _('Как с нами работать')), + # ('slider', _('Галерея слайдов')), ) -class Block(BaseModelViewPage): + +class Block_Abstract(BaseModelViewPage): + + class Meta: + verbose_name = _('Блок') + verbose_name_plural = _('Блоки') + abstract = True + + +class Block(Block_Abstract): content_type = models.ForeignKey(ContentType, on_delete=models.SET_NULL, null=True) object_id = models.PositiveIntegerField() content_object = GenericForeignKey('content_type', 'object_id') - block_type = models.CharField(max_length=100, choices=block_type_choices, verbose_name=_('Тип блока'), default='photo_n_text') + block_type = models.CharField(max_length=100, choices=block_type_choices, verbose_name=_('Тип блока'), + default='photo_n_text') url = models.TextField(verbose_name=_('URL привязанной страницы'), null=True, blank=True) @@ -38,6 +49,11 @@ class Block(BaseModelViewPage): but_title = models.CharField(max_length=100, verbose_name=_('Текст на кнопке'), null=True, blank=True) but_color = ColorField(verbose_name=_('Цвет кнопки'), default='#000000') + but_icon = models.FileField( + upload_to='uploads/', verbose_name=_('Пиктограмма для кнопки'), null=True, blank=True, + validators=[validate_file_extension] + ) + child_in_row_count = models.PositiveSmallIntegerField( verbose_name=_('Количество дочерних элементов в строке'), default=3) @@ -47,6 +63,10 @@ class Block(BaseModelViewPage): + + + + class WidgetForBlock(BaseModel): block = models.ForeignKey( @@ -57,7 +77,8 @@ class WidgetForBlock(BaseModel): title = models.TextField(verbose_name=_('Заголовок'), null=True, blank=True) description = RichTextUploadingField(verbose_name=_('Краткое описание'), null=True, blank=True) - picture = models.ImageField(upload_to='uploads/', verbose_name=_('Картинка'), null=True, blank=True) + picture = models.FileField(upload_to='uploads/', verbose_name=_('Картинка'), null=True, blank=True, + validators=[validate_file_extension]) # block_type = models.CharField(max_length=100, choices=block_type_choices, verbose_name=_('Тип блока'), default='photo_n_text') @@ -68,6 +89,11 @@ class WidgetForBlock(BaseModel): but_title = models.CharField(max_length=100, verbose_name=_('Текст на кнопке'), null=True, blank=True) but_color = ColorField(verbose_name=_('Цвет кнопки'), default='#000000') + but_icon = models.FileField( + upload_to='uploads/', verbose_name=_('Пиктограмма для кнопки'), null=True, blank=True, + validators=[validate_file_extension] + ) + class Meta: verbose_name = _('Виджет в блоке') @@ -79,8 +105,8 @@ class Option(BaseModel): opt_type = models.CharField(max_length=250, verbose_name=_('Тип'), blank=True, null=True) prefix = models.CharField(max_length=250, verbose_name=_('Префикс'), blank=True, null=True) value = models.CharField(max_length=250, verbose_name=_('Значение')) - picture = models.ImageField(upload_to='uploads/', verbose_name=_('Миниатюра'), null=True, blank=True, - help_text=u'') + picture = models.FileField(upload_to='uploads/', verbose_name=_('Миниатюра'), null=True, blank=True, + validators=[validate_file_extension]) class Meta: verbose_name = _('Параметр') diff --git a/GeneralApp/validators.py b/GeneralApp/validators.py new file mode 100644 index 0000000..ac8900a --- /dev/null +++ b/GeneralApp/validators.py @@ -0,0 +1,8 @@ +import os +from django.core.exceptions import ValidationError + +def validate_file_extension(value): + ext = os.path.splitext(value.name)[1] + valid_extensions = ['.jpg', '.jpeg', '.png', '.svg'] + if not ext.lower() in valid_extensions: + raise ValidationError('Unsupported file extension.') \ No newline at end of file diff --git a/ServicesApp/admin.py b/ServicesApp/admin.py index 610e296..d2c6d59 100644 --- a/ServicesApp/admin.py +++ b/ServicesApp/admin.py @@ -16,6 +16,30 @@ def sets_for_formfield_for_dbfield(field, db_field): +class Admin_StackedInline_BlockPluginPresentation(Admin_Trans_GenericBaseIconStackedInline): +# class Admin_StackedInline_Block(Admin_Trans_GenericBaseIconStackedInline): + + def formfield_for_dbfield(self, db_field, request, **kwargs): + field = super(Admin_StackedInline_BlockPluginPresentation, self).formfield_for_dbfield(db_field, request, **kwargs) + return sets_for_formfield_for_dbfield(field, db_field) + + model = BlockPluginPresentation + extra = 0 + max_num = 1 + fieldsets = [ + (None, { + 'classes': [], + 'fields': [ + 'pre_title', 'title', 'name', 'description', 'picture', + ('but1_title', 'but1_icon', 'but1_url'), + ('but2_title', 'but2_icon', 'but2_url'), + # ('order',), + ] + }) + ] + + + # class Admin_StaticPage(NestedModelAdmin, Admin_Trans_BaseModelViewPage): class Admin_Section(SuperModelAdmin, Admin_Trans_BaseModelViewPage): @@ -54,7 +78,11 @@ class Admin_Section(SuperModelAdmin, Admin_Trans_BaseModelViewPage): search_fields = ['name', 'title'] # filter_horizontal = ['options'] - inlines = [Admin_StackedInline_Slide, Admin_StackedInline_Block] + inlines = [ + Admin_StackedInline_Slide, + Admin_StackedInline_BlockPluginPresentation, + Admin_StackedInline_Block + ] def has_delete_permission(self, request, obj=None): if request.user.is_superuser: diff --git a/ServicesApp/migrations/0003_blockpluginpresentation.py b/ServicesApp/migrations/0003_blockpluginpresentation.py new file mode 100644 index 0000000..995b5cd --- /dev/null +++ b/ServicesApp/migrations/0003_blockpluginpresentation.py @@ -0,0 +1,65 @@ +# Generated by Django 4.2.7 on 2023-11-27 16:25 + +import ckeditor_uploader.fields +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('contenttypes', '0002_remove_content_type_name'), + ('ServicesApp', '0002_alter_service_url'), + ] + + operations = [ + migrations.CreateModel( + name='BlockPluginPresentation', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.TextField(blank=True, help_text='Название', null=True, verbose_name='Название')), + ('name_ru', models.TextField(blank=True, help_text='Название', null=True, verbose_name='Название')), + ('name_en', models.TextField(blank=True, help_text='Название', null=True, verbose_name='Название')), + ('name_plural', models.TextField(blank=True, null=True, verbose_name='Название (множественное число)')), + ('order', models.IntegerField(blank=True, null=True, verbose_name='Очередность отображения')), + ('createDT', models.DateTimeField(auto_now_add=True, verbose_name='Дата и время создания')), + ('modifiedDT', models.DateTimeField(blank=True, null=True, verbose_name='Дата и время последнего изменения')), + ('enable', models.BooleanField(db_index=True, default=True, verbose_name='Включено')), + ('json_data', models.JSONField(blank=True, default=dict, verbose_name='Дополнительные данные')), + ('url', models.TextField(help_text='можно изменить адрес страницы (!!! ВНИМАНИЕ !!! поисковые системы потеряют страницу и найдут лишь спустя неделю...месяц)', unique=True, verbose_name='URL привязанной страницы')), + ('title', models.TextField(blank=True, null=True, verbose_name='Заголовок')), + ('title_ru', models.TextField(blank=True, null=True, verbose_name='Заголовок')), + ('title_en', models.TextField(blank=True, null=True, verbose_name='Заголовок')), + ('description', ckeditor_uploader.fields.RichTextUploadingField(blank=True, help_text='краткое описание страницы (до 240 символов)', null=True, verbose_name='Краткое описание')), + ('description_ru', ckeditor_uploader.fields.RichTextUploadingField(blank=True, help_text='краткое описание страницы (до 240 символов)', null=True, verbose_name='Краткое описание')), + ('description_en', ckeditor_uploader.fields.RichTextUploadingField(blank=True, help_text='краткое описание страницы (до 240 символов)', null=True, verbose_name='Краткое описание')), + ('text', ckeditor_uploader.fields.RichTextUploadingField(blank=True, null=True, verbose_name='Полное описание')), + ('text_ru', ckeditor_uploader.fields.RichTextUploadingField(blank=True, null=True, verbose_name='Полное описание')), + ('text_en', ckeditor_uploader.fields.RichTextUploadingField(blank=True, null=True, verbose_name='Полное описание')), + ('picture', models.ImageField(blank=True, null=True, upload_to='uploads/', verbose_name='Картинка')), + ('visible', models.BooleanField(default=True, verbose_name='Отображать')), + ('seo_title', models.CharField(blank=True, max_length=250, null=True, verbose_name='Title (80 знаков)')), + ('seo_description', models.CharField(blank=True, max_length=250, null=True, verbose_name='Description (150 знаков)')), + ('seo_keywords', models.CharField(blank=True, max_length=250, null=True, verbose_name='Keywords (200 знаков)')), + ('seo_text', ckeditor_uploader.fields.RichTextUploadingField(blank=True, null=True, verbose_name='Текст SEO статьи')), + ('FAQ_title', models.CharField(blank=True, max_length=250, null=True, verbose_name='FAQ Заголовок')), + ('object_id', models.PositiveIntegerField()), + ('pre_title', models.CharField(blank=True, max_length=250, null=True, verbose_name='Текст перед заголовком')), + ('pre_title_ru', models.CharField(blank=True, max_length=250, null=True, verbose_name='Текст перед заголовком')), + ('pre_title_en', models.CharField(blank=True, max_length=250, null=True, verbose_name='Текст перед заголовком')), + ('but1_title', models.CharField(blank=True, max_length=100, null=True, verbose_name='Текст на кнопке 1')), + ('but1_title_ru', models.CharField(blank=True, max_length=100, null=True, verbose_name='Текст на кнопке 1')), + ('but1_title_en', models.CharField(blank=True, max_length=100, null=True, verbose_name='Текст на кнопке 1')), + ('but2_title', models.CharField(blank=True, max_length=100, null=True, verbose_name='Текст на кнопке 2')), + ('but2_title_ru', models.CharField(blank=True, max_length=100, null=True, verbose_name='Текст на кнопке 2')), + ('but2_title_en', models.CharField(blank=True, max_length=100, null=True, verbose_name='Текст на кнопке 2')), + ('but1_url', models.TextField(blank=True, null=True, verbose_name='URL привязанной страницы к кнопке 1')), + ('but2_url', models.TextField(blank=True, null=True, verbose_name='URL привязанной страницы к кнопке 2')), + ('content_type', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='contenttypes.contenttype')), + ], + options={ + 'verbose_name': 'Блок презентации плагина', + 'verbose_name_plural': 'Блоки презентации плагина', + }, + ), + ] diff --git a/ServicesApp/migrations/0004_alter_blockpluginpresentation_picture_and_more.py b/ServicesApp/migrations/0004_alter_blockpluginpresentation_picture_and_more.py new file mode 100644 index 0000000..088d9fe --- /dev/null +++ b/ServicesApp/migrations/0004_alter_blockpluginpresentation_picture_and_more.py @@ -0,0 +1,29 @@ +# Generated by Django 4.2.7 on 2023-11-27 17:13 + +import BaseModels.base_models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ServicesApp', '0003_blockpluginpresentation'), + ] + + operations = [ + migrations.AlterField( + model_name='blockpluginpresentation', + name='picture', + field=models.FileField(blank=True, null=True, upload_to='uploads/', validators=[BaseModels.base_models.validate_file_extension], verbose_name='Картинка'), + ), + migrations.AlterField( + model_name='section', + name='picture', + field=models.FileField(blank=True, null=True, upload_to='uploads/', validators=[BaseModels.base_models.validate_file_extension], verbose_name='Картинка'), + ), + migrations.AlterField( + model_name='service', + name='picture', + field=models.FileField(blank=True, null=True, upload_to='uploads/', validators=[BaseModels.base_models.validate_file_extension], verbose_name='Картинка'), + ), + ] diff --git a/ServicesApp/migrations/0005_blockpluginpresentation_but1_icon_and_more.py b/ServicesApp/migrations/0005_blockpluginpresentation_but1_icon_and_more.py new file mode 100644 index 0000000..7517366 --- /dev/null +++ b/ServicesApp/migrations/0005_blockpluginpresentation_but1_icon_and_more.py @@ -0,0 +1,24 @@ +# Generated by Django 4.2.7 on 2023-11-27 17:28 + +import BaseModels.base_models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ServicesApp', '0004_alter_blockpluginpresentation_picture_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='blockpluginpresentation', + name='but1_icon', + field=models.FileField(blank=True, null=True, upload_to='uploads/', validators=[BaseModels.base_models.validate_file_extension], verbose_name='Пиктограмма для кнопки 1'), + ), + migrations.AddField( + model_name='blockpluginpresentation', + name='but2_icon', + field=models.FileField(blank=True, null=True, upload_to='uploads/', validators=[BaseModels.base_models.validate_file_extension], verbose_name='Пиктограмма для кнопки 2'), + ), + ] diff --git a/ServicesApp/models.py b/ServicesApp/models.py index 2589eee..1ce2d21 100644 --- a/ServicesApp/models.py +++ b/ServicesApp/models.py @@ -1,8 +1,48 @@ from django.db import models from BaseModels.base_models import * from django.utils.translation import gettext_lazy as _ +from GeneralApp.models import Block_Abstract +from django.contrib.contenttypes.models import ContentType +from django.contrib.contenttypes.fields import GenericForeignKey +from django.contrib.contenttypes.fields import GenericRelation +from django.core.validators import validate_image_file_extension + +class BlockPluginPresentation(Block_Abstract): + from BaseModels.base_models import Manager_Enabled + objects = models.Manager() + enabled_objs = Manager_Enabled() + + content_type = models.ForeignKey(ContentType, on_delete=models.SET_NULL, null=True) + object_id = models.PositiveIntegerField() + content_object = GenericForeignKey('content_type', 'object_id') + + pre_title = models.CharField(max_length=250, verbose_name=_('Текст перед заголовком'), null=True, blank=True) + + but1_title = models.CharField(max_length=100, verbose_name=_('Текст на кнопке 1'), null=True, blank=True) + but2_title = models.CharField(max_length=100, verbose_name=_('Текст на кнопке 2'), null=True, blank=True) + + but1_url = models.TextField(verbose_name=_('URL привязанной страницы к кнопке 1'), null=True, blank=True) + but2_url = models.TextField(verbose_name=_('URL привязанной страницы к кнопке 2'), null=True, blank=True) + + but1_icon = models.FileField( + upload_to='uploads/', verbose_name=_('Пиктограмма для кнопки 1'), null=True, blank=True, + validators=[validate_file_extension] + ) + but2_icon = models.FileField( + upload_to='uploads/', verbose_name=_('Пиктограмма для кнопки 2'), null=True, blank=True, + validators=[validate_file_extension] + ) + + class Meta: + verbose_name = _('Блок презентации плагина') + verbose_name_plural = _('Блоки презентации плагина') + class Section(BaseModelViewPage): + + plugin_presentation = GenericRelation('ServicesApp.BlockPluginPresentation', + related_query_name='grel_%(class)s_for_block_plugin_presentation') + class Meta: verbose_name = _('Раздел сайта') verbose_name_plural = _('Разделы сайта') @@ -22,6 +62,9 @@ class Service(BaseModelViewPage): on_delete=models.SET_NULL, related_name='rel_children_for_service', null=True, blank=True ) + + + class Meta: verbose_name = _('Услуга') verbose_name_plural = _('Услуги') \ No newline at end of file diff --git a/ServicesApp/translation.py b/ServicesApp/translation.py index 3426165..a14184a 100644 --- a/ServicesApp/translation.py +++ b/ServicesApp/translation.py @@ -2,6 +2,13 @@ from modeltranslation.translator import translator, TranslationOptions from .models import * +class BlockPluginPresentation_TranslationOptions(TranslationOptions): + fields = ( + 'name', 'description', 'text', 'title', 'pre_title', 'but1_title', 'but2_title' + ) +translator.register(BlockPluginPresentation, BlockPluginPresentation_TranslationOptions) + + class Section_TranslationOptions(TranslationOptions): fields = ( 'name', 'description', 'text', 'title', 'FAQ_title', 'seo_title', 'seo_description', 'seo_text' diff --git a/templates/blocks/b_3d_s_d.html b/templates/blocks/b_3d_s_d.html index 2113c3b..1329b5e 100644 --- a/templates/blocks/b_3d_s_d.html +++ b/templates/blocks/b_3d_s_d.html @@ -1,33 +1,58 @@ {% load static %}