From 53687e240d88bbcb78e06629c7e218d0c467f567 Mon Sep 17 00:00:00 2001 From: SDE Date: Sun, 26 Nov 2023 14:31:30 +0300 Subject: [PATCH] 0.0.2 init, blocks prepare --- BaseModels/base_models.py | 4 +- GeneralApp/admin.py | 89 ++++++++++++++---- ...ve_block_background_image_left_and_more.py | 68 +++++++++++++ GeneralApp/migrations/0003_alter_block_url.py | 18 ++++ ...er_block_options_alter_block_block_type.py | 22 +++++ GeneralApp/migrations/0005_widgetforblock.py | 41 ++++++++ ...ck_type_en_block_block_type_ru_and_more.py | 74 +++++++++++++++ GeneralApp/models.py | 74 +++++++++++++-- GeneralApp/translation.py | 10 +- ServicesApp/__init__.py | 0 ServicesApp/admin.py | 3 + ServicesApp/apps.py | 6 ++ ServicesApp/migrations/__init__.py | 0 ServicesApp/models.py | 24 +++++ ServicesApp/tests.py | 3 + ServicesApp/views.py | 3 + db.sqlite3 | Bin 180224 -> 221184 bytes pAerBim/settings.py | 6 +- pAerBim/urls.py | 4 +- sets/admin.py | 59 +++++++++++- 20 files changed, 475 insertions(+), 33 deletions(-) create mode 100644 GeneralApp/migrations/0002_remove_block_background_image_left_and_more.py create mode 100644 GeneralApp/migrations/0003_alter_block_url.py create mode 100644 GeneralApp/migrations/0004_alter_block_options_alter_block_block_type.py create mode 100644 GeneralApp/migrations/0005_widgetforblock.py create mode 100644 GeneralApp/migrations/0006_block_block_type_en_block_block_type_ru_and_more.py create mode 100644 ServicesApp/__init__.py create mode 100644 ServicesApp/admin.py create mode 100644 ServicesApp/apps.py create mode 100644 ServicesApp/migrations/__init__.py create mode 100644 ServicesApp/models.py create mode 100644 ServicesApp/tests.py create mode 100644 ServicesApp/views.py diff --git a/BaseModels/base_models.py b/BaseModels/base_models.py index f38b177..f5ac624 100644 --- a/BaseModels/base_models.py +++ b/BaseModels/base_models.py @@ -95,8 +95,8 @@ class BaseModelViewPage(BaseModel): help_text=u'') # 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) - background_image_right = models.ImageField(verbose_name=_('Правая подложка'), blank=True, null=True) + # background_image_left = models.ImageField(verbose_name=_('Левая подложка'), blank=True, null=True) + # background_image_right = models.ImageField(verbose_name=_('Правая подложка'), blank=True, null=True) seo_title = models.CharField(max_length=250, verbose_name=_('Title (80 знаков)'), null=True, blank=True) diff --git a/GeneralApp/admin.py b/GeneralApp/admin.py index daa9135..2a40f9e 100644 --- a/GeneralApp/admin.py +++ b/GeneralApp/admin.py @@ -1,8 +1,75 @@ from sets.admin import * from .models import * from django.contrib import admin +from django.forms import widgets +# from nested_inline.admin import NestedStackedInline, NestedTabularInline, NestedModelAdmin, NestedInline +from super_inlines.admin import SuperInlineModelAdmin, SuperModelAdmin + + +def sets_for_formfield_for_dbfield(field, db_field): + if db_field.name == 'url' or db_field.name == 'name' or db_field.name == 'title' or db_field.name == 'name_plural': + field.widget = widgets.TextInput(attrs={'style': 'width: 30%; height: 20px;'}) + if db_field.name == 'description': + field.widget = widgets.Textarea(attrs={'style': 'width: 30%; height: 100px;'}) + return field + + +class Admin_Inline_WidgetForBlock(SuperInlineModelAdmin, Admin_Trans_BaseIconStackedInline): +# class Admin_Inline_WidgetForBlock(Admin_Trans_BaseIconTabularInline, SuperInlineModelAdmin): + + def formfield_for_dbfield(self, db_field, request, **kwargs): + field = super(Admin_Inline_WidgetForBlock, self).formfield_for_dbfield(db_field, request, **kwargs) + return sets_for_formfield_for_dbfield(field, db_field) + # return field + + model = WidgetForBlock + extra = 0 + # fields = ['title', 'description', 'picture', 'bg_color', 'but_title', 'but_color', 'url'] + fieldsets = [ + (None, { + 'classes': [], + 'fields': [ + ('title', 'description', 'picture'), + ('bg_color', ), + ('but_title', 'but_color'), + ('url',), + ] + }) + ] + + + +class Admin_StackedInline_Block(Admin_Trans_GenericBaseIconStackedInline, SuperInlineModelAdmin): +# class Admin_StackedInline_Block(Admin_Trans_GenericBaseIconStackedInline): + + def formfield_for_dbfield(self, db_field, request, **kwargs): + field = super(Admin_StackedInline_Block, self).formfield_for_dbfield(db_field, request, **kwargs) + return sets_for_formfield_for_dbfield(field, db_field) + + model = Block + extra = 0 + fieldsets = [ + (None, { + 'classes': [], + 'fields': [ + ('block_type', 'title', 'description', 'picture'), + ('bg_color', ), + ('but_title', 'but_color'), + ('url',), + ('child_in_row_count',), + ] + }) + ] + + inlines = [Admin_Inline_WidgetForBlock] + + + + + +# class Admin_StaticPage(NestedModelAdmin, Admin_Trans_BaseModelViewPage): +class Admin_StaticPage(SuperModelAdmin, Admin_Trans_BaseModelViewPage): -class Admin_StaticPage(Admin_Trans_BaseModelViewPage): fieldsets = [ (None, { @@ -36,6 +103,8 @@ class Admin_StaticPage(Admin_Trans_BaseModelViewPage): search_fields = ['name', 'title'] # filter_horizontal = ['options'] + inlines = [Admin_StackedInline_Block] + def has_delete_permission(self, request, obj=None): if request.user.is_superuser: return True @@ -45,23 +114,11 @@ class Admin_StaticPage(Admin_Trans_BaseModelViewPage): admin.site.register(StaticPage,Admin_StaticPage) -class Admin_Block(Admin_BaseBlock): +class Admin_Block(Admin_Trans_BaseModelViewPage): - def get_fieldsets(self, request, obj=None): - fieldsets = super(type(self), self).get_fieldsets(request, obj) - if not request.user.is_superuser and obj.name and obj.name in ('About US', 'machines', 'works'): - fieldsets[0][1]['fields'].pop(0) - fieldsets.insert( - 1, ('Контент', { - 'classes': ['wide'], - 'fields': ( - 'title', 'description', 'text', - 'picture', - ) - }) - ) - return fieldsets + + inlines = [Admin_StackedInline_Block] def has_delete_permission(self, request, obj=None): if request.user.is_superuser: diff --git a/GeneralApp/migrations/0002_remove_block_background_image_left_and_more.py b/GeneralApp/migrations/0002_remove_block_background_image_left_and_more.py new file mode 100644 index 0000000..26845e4 --- /dev/null +++ b/GeneralApp/migrations/0002_remove_block_background_image_left_and_more.py @@ -0,0 +1,68 @@ +# Generated by Django 4.2.7 on 2023-11-21 16:49 + +import colorfield.fields +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('contenttypes', '0002_remove_content_type_name'), + ('GeneralApp', '0001_initial'), + ] + + operations = [ + migrations.RemoveField( + model_name='block', + name='background_image_left', + ), + migrations.RemoveField( + model_name='block', + name='background_image_right', + ), + migrations.RemoveField( + model_name='staticpage', + name='background_image_left', + ), + migrations.RemoveField( + model_name='staticpage', + name='background_image_right', + ), + migrations.AddField( + model_name='block', + name='bg_color', + field=colorfield.fields.ColorField(default='#FFFFFF', image_field=None, max_length=25, samples=None, verbose_name='Цвет фона'), + ), + migrations.AddField( + model_name='block', + name='block_type', + field=models.CharField(default='photo_n_text', max_length=100, verbose_name='Тип блока'), + ), + migrations.AddField( + model_name='block', + name='but_color', + field=colorfield.fields.ColorField(default='#000000', image_field=None, max_length=25, samples=None, verbose_name='Цвет кнопки'), + ), + migrations.AddField( + model_name='block', + name='but_title', + field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Текст на кнопке'), + ), + migrations.AddField( + model_name='block', + name='child_in_row_count', + field=models.PositiveSmallIntegerField(default=3, verbose_name='Количество дочерних элементов в строке'), + ), + migrations.AddField( + model_name='block', + name='content_type', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='contenttypes.contenttype'), + ), + migrations.AddField( + model_name='block', + name='object_id', + field=models.PositiveIntegerField(default=0), + preserve_default=False, + ), + ] diff --git a/GeneralApp/migrations/0003_alter_block_url.py b/GeneralApp/migrations/0003_alter_block_url.py new file mode 100644 index 0000000..b03e658 --- /dev/null +++ b/GeneralApp/migrations/0003_alter_block_url.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.7 on 2023-11-21 16:51 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('GeneralApp', '0002_remove_block_background_image_left_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='block', + name='url', + field=models.TextField(blank=True, null=True, verbose_name='URL привязанной страницы'), + ), + ] diff --git a/GeneralApp/migrations/0004_alter_block_options_alter_block_block_type.py b/GeneralApp/migrations/0004_alter_block_options_alter_block_block_type.py new file mode 100644 index 0000000..09f4e38 --- /dev/null +++ b/GeneralApp/migrations/0004_alter_block_options_alter_block_block_type.py @@ -0,0 +1,22 @@ +# Generated by Django 4.2.7 on 2023-11-22 16:15 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('GeneralApp', '0003_alter_block_url'), + ] + + operations = [ + migrations.AlterModelOptions( + name='block', + options={'verbose_name': 'Блок на странице', 'verbose_name_plural': 'Блоки на странице'}, + ), + migrations.AlterField( + model_name='block', + name='block_type', + field=models.CharField(choices=[('photo_n_text', 'Фото + текст')], default='photo_n_text', max_length=100, verbose_name='Тип блока'), + ), + ] diff --git a/GeneralApp/migrations/0005_widgetforblock.py b/GeneralApp/migrations/0005_widgetforblock.py new file mode 100644 index 0000000..4f1a2c3 --- /dev/null +++ b/GeneralApp/migrations/0005_widgetforblock.py @@ -0,0 +1,41 @@ +# Generated by Django 4.2.7 on 2023-11-24 14:36 + +import ckeditor_uploader.fields +import colorfield.fields +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('GeneralApp', '0004_alter_block_options_alter_block_block_type'), + ] + + operations = [ + migrations.CreateModel( + name='WidgetForBlock', + 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_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='Дополнительные данные')), + ('title', models.TextField(blank=True, null=True, verbose_name='Заголовок')), + ('description', ckeditor_uploader.fields.RichTextUploadingField(blank=True, null=True, verbose_name='Краткое описание')), + ('picture', models.ImageField(blank=True, null=True, upload_to='uploads/', verbose_name='Картинка')), + ('url', models.TextField(blank=True, null=True, verbose_name='URL привязанной страницы')), + ('bg_color', colorfield.fields.ColorField(default='#FFFFFF', image_field=None, max_length=25, samples=None, verbose_name='Цвет фона')), + ('but_title', models.CharField(blank=True, max_length=100, null=True, verbose_name='Текст на кнопке')), + ('but_color', colorfield.fields.ColorField(default='#000000', image_field=None, max_length=25, samples=None, verbose_name='Цвет кнопки')), + ('block', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='rel_widgets_for_block', to='GeneralApp.block', verbose_name='Родительский блок')), + ], + options={ + 'verbose_name': 'Виджет в блоке', + 'verbose_name_plural': 'Виджеты в блоках', + }, + ), + ] diff --git a/GeneralApp/migrations/0006_block_block_type_en_block_block_type_ru_and_more.py b/GeneralApp/migrations/0006_block_block_type_en_block_block_type_ru_and_more.py new file mode 100644 index 0000000..f1f0d24 --- /dev/null +++ b/GeneralApp/migrations/0006_block_block_type_en_block_block_type_ru_and_more.py @@ -0,0 +1,74 @@ +# Generated by Django 4.2.7 on 2023-11-24 14:47 + +import ckeditor_uploader.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('GeneralApp', '0005_widgetforblock'), + ] + + operations = [ + migrations.AddField( + model_name='block', + name='block_type_en', + field=models.CharField(choices=[('photo_n_text', 'Фото + текст')], default='photo_n_text', max_length=100, null=True, verbose_name='Тип блока'), + ), + migrations.AddField( + model_name='block', + name='block_type_ru', + field=models.CharField(choices=[('photo_n_text', 'Фото + текст')], default='photo_n_text', max_length=100, null=True, verbose_name='Тип блока'), + ), + migrations.AddField( + model_name='block', + name='but_title_en', + field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Текст на кнопке'), + ), + migrations.AddField( + model_name='block', + name='but_title_ru', + field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Текст на кнопке'), + ), + migrations.AddField( + model_name='widgetforblock', + name='but_title_en', + field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Текст на кнопке'), + ), + migrations.AddField( + model_name='widgetforblock', + name='but_title_ru', + field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Текст на кнопке'), + ), + migrations.AddField( + model_name='widgetforblock', + name='description_en', + field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, null=True, verbose_name='Краткое описание'), + ), + migrations.AddField( + model_name='widgetforblock', + name='description_ru', + field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, null=True, verbose_name='Краткое описание'), + ), + migrations.AddField( + model_name='widgetforblock', + name='name_en', + field=models.TextField(blank=True, help_text='Название', null=True, verbose_name='Название'), + ), + migrations.AddField( + model_name='widgetforblock', + name='name_ru', + field=models.TextField(blank=True, help_text='Название', null=True, verbose_name='Название'), + ), + migrations.AddField( + model_name='widgetforblock', + name='title_en', + field=models.TextField(blank=True, null=True, verbose_name='Заголовок'), + ), + migrations.AddField( + model_name='widgetforblock', + name='title_ru', + field=models.TextField(blank=True, null=True, verbose_name='Заголовок'), + ), + ] diff --git a/GeneralApp/models.py b/GeneralApp/models.py index 5f04a1a..91ff4e4 100644 --- a/GeneralApp/models.py +++ b/GeneralApp/models.py @@ -3,6 +3,11 @@ from BaseModels.base_models import BaseModelViewPage, BaseModel from django.utils.translation import gettext_lazy as _ # from ckeditor.fields import RichTextField from ckeditor_uploader.fields import RichTextUploadingField +# from colorfield.fields import ColorField +from django.contrib.contenttypes.models import ContentType +from django.contrib.contenttypes.fields import GenericForeignKey +from django.contrib.contenttypes.fields import GenericRelation +from colorfield.fields import ColorField class StaticPage(BaseModelViewPage): promo_header = models.BooleanField(verbose_name='Промо-хэдер', default=False) @@ -11,15 +16,69 @@ class StaticPage(BaseModelViewPage): verbose_name = _('Статическая страница') verbose_name_plural = _('Статические страницы') + +block_type_choices = ( + ('photo_n_text', _('Фото + текст')), + ('photo150_n_title', _('Фото 150x150 + заголовок')), + ('slider', _('Галерея слайдов')), +) + class Block(BaseModelViewPage): + + 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') + + url = models.TextField(verbose_name=_('URL привязанной страницы'), null=True, blank=True) + + bg_color = ColorField(verbose_name=_('Цвет фона'), default='#FFFFFF') + + but_title = models.CharField(max_length=100, verbose_name=_('Текст на кнопке'), null=True, blank=True) + but_color = ColorField(verbose_name=_('Цвет кнопки'), default='#000000') + + child_in_row_count = models.PositiveSmallIntegerField( + verbose_name=_('Количество дочерних элементов в строке'), default=3) + class Meta: verbose_name = _('Блок на странице') - verbose_name_plural = _('Блоки на страницах') + verbose_name_plural = _('Блоки на странице') + + + +class WidgetForBlock(BaseModel): + + block = models.ForeignKey( + Block, verbose_name=_('Родительский блок'), on_delete=models.CASCADE, + related_name='rel_widgets_for_block' + ) + + 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) + + # 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) + + bg_color = ColorField(verbose_name=_('Цвет фона'), default='#FFFFFF') + + but_title = models.CharField(max_length=100, verbose_name=_('Текст на кнопке'), null=True, blank=True) + but_color = ColorField(verbose_name=_('Цвет кнопки'), default='#000000') + + + class Meta: + verbose_name = _('Виджет в блоке') + verbose_name_plural = _('Виджеты в блоке') + + 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='Значение') + 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'') @@ -29,15 +88,12 @@ class Option(BaseModel): class FAQitem(BaseModel): - from django.contrib.contenttypes.models import ContentType - from django.contrib.contenttypes.fields import GenericForeignKey - content_type = models.ForeignKey(ContentType, on_delete=models.SET_NULL, null=True) object_id = models.PositiveIntegerField() content_object = GenericForeignKey('content_type', 'object_id') - question = models.TextField(verbose_name='Вопрос') - answer = RichTextUploadingField(verbose_name='Ответ') + question = models.TextField(verbose_name=_('Вопрос')) + answer = RichTextUploadingField(verbose_name=_('Ответ')) def __str__(self): if self.question: diff --git a/GeneralApp/translation.py b/GeneralApp/translation.py index 59a74b2..5996365 100644 --- a/GeneralApp/translation.py +++ b/GeneralApp/translation.py @@ -10,11 +10,19 @@ translator.register(StaticPage, StaticPage_TranslationOptions) class Block_TranslationOptions(TranslationOptions): fields = ( - 'name', 'description', 'text', 'title', 'FAQ_title' + 'name', 'description', 'text', 'title', 'FAQ_title', 'but_title' ) translator.register(Block, Block_TranslationOptions) + +class WidgetForBlock_TranslationOptions(TranslationOptions): + fields = ( + 'name', 'description', 'title', 'but_title' + ) +translator.register(WidgetForBlock, WidgetForBlock_TranslationOptions) + + class FAQitem_TranslationOptions(TranslationOptions): fields = ( 'name', 'question', 'answer' diff --git a/ServicesApp/__init__.py b/ServicesApp/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ServicesApp/admin.py b/ServicesApp/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/ServicesApp/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/ServicesApp/apps.py b/ServicesApp/apps.py new file mode 100644 index 0000000..4168ce2 --- /dev/null +++ b/ServicesApp/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class ServicesappConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'ServicesApp' diff --git a/ServicesApp/migrations/__init__.py b/ServicesApp/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ServicesApp/models.py b/ServicesApp/models.py new file mode 100644 index 0000000..6f007e4 --- /dev/null +++ b/ServicesApp/models.py @@ -0,0 +1,24 @@ +from django.db import models +from BaseModels.base_models import * +from django.utils.translation import gettext_lazy as _ + +class Section(BaseModelViewPage): + class Meta: + verbose_name = _('Раздел сайта') + verbose_name_plural = _('Разделы сайта') + + +class Service(BaseModelViewPage): + section = models.ForeignKey( + Section, verbose_name=_('Раздел'), + on_delete=models.SET_NULL, related_name='rel_services_for_section', + null=True, blank=True + ) + parent_service = models.ForeignKey( + 'Service', verbose_name=_('Родитель'), + 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/tests.py b/ServicesApp/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/ServicesApp/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/ServicesApp/views.py b/ServicesApp/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/ServicesApp/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/db.sqlite3 b/db.sqlite3 index d5802e9b38b25e4b88501573221608abeff818fe..113c873dc16097bf7a2eb411fe0b77c83dba598e 100644 GIT binary patch literal 221184 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 diff --git a/pAerBim/settings.py b/pAerBim/settings.py index 6e75709..1cf279d 100644 --- a/pAerBim/settings.py +++ b/pAerBim/settings.py @@ -31,7 +31,11 @@ ALLOWED_HOSTS = [] # Application definition INSTALLED_APPS = [ + 'colorfield', 'modeltranslation', + "admin_interface", + + 'super_inlines', 'django.contrib.admin', 'django.contrib.auth', @@ -41,7 +45,7 @@ INSTALLED_APPS = [ 'django.contrib.staticfiles', 'django.contrib.humanize', - 'colorfield', + # 'nested_admin', 'ckeditor', 'ckeditor_uploader', diff --git a/pAerBim/urls.py b/pAerBim/urls.py index 1600927..389505f 100644 --- a/pAerBim/urls.py +++ b/pAerBim/urls.py @@ -8,16 +8,16 @@ urlpatterns = [ # path('admin/', admin.site.urls), path('ckeditor/', include('ckeditor_uploader.urls')), path('i18n/', include('django.conf.urls.i18n')), - + # path('_nested_admin/', include('nested_admin.urls')), ] from django.conf.urls.i18n import i18n_patterns urlpatterns += i18n_patterns( + path('admin/', admin.site.urls), path('', include('GeneralApp.urls')), - ) urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) \ No newline at end of file diff --git a/sets/admin.py b/sets/admin.py index 7300b8d..045d611 100644 --- a/sets/admin.py +++ b/sets/admin.py @@ -1,4 +1,9 @@ from BaseModels.admin_utils import Admin_GenericBaseIconStackedInline, Admin_BaseIconModel +from modeltranslation.admin import (TranslationAdmin, + TranslationGenericStackedInline, + TranslationGenericTabularInline, + TranslationTabularInline, + TranslationStackedInline) from copy import deepcopy class AdminStacked_FAQitem(Admin_GenericBaseIconStackedInline): @@ -98,7 +103,7 @@ class Admin_BaseModelViewPage(Admin_BaseIconModel): -from modeltranslation.admin import TranslationAdmin + class AdminTranslationBase(TranslationAdmin): # def formfield_for_dbfield(self, db_field, **kwargs): @@ -126,4 +131,54 @@ class Admin_Trans_BaseModel(Admin_BaseModel, AdminTranslationBase): # pass class Admin_Trans_BaseModelViewPage(Admin_BaseModelViewPage, AdminTranslationBase): - pass \ No newline at end of file + pass + +class Admin_Trans_GenericBaseIconStackedInline(TranslationGenericStackedInline): + class Media: + js = ( + 'modeltranslation/js/force_jquery.js', + 'http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js', + 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.2/jquery-ui.min.js', + 'modeltranslation/js/tabbed_translation_fields.js', + ) + css = { + 'screen': ('modeltranslation/css/tabbed_translation_fields.css',), + } + +class Admin_Trans_GenericBaseIconTabularInline(TranslationGenericTabularInline): + class Media: + js = ( + 'modeltranslation/js/force_jquery.js', + 'http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js', + 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.2/jquery-ui.min.js', + 'modeltranslation/js/tabbed_translation_fields.js', + ) + css = { + 'screen': ('modeltranslation/css/tabbed_translation_fields.css',), + } + + +class Admin_Trans_BaseIconTabularInline(TranslationTabularInline): + class Media: + js = ( + 'modeltranslation/js/force_jquery.js', + 'http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js', + 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.2/jquery-ui.min.js', + 'modeltranslation/js/tabbed_translation_fields.js', + ) + css = { + 'screen': ('modeltranslation/css/tabbed_translation_fields.css',), + } + + +class Admin_Trans_BaseIconStackedInline(TranslationStackedInline): + class Media: + js = ( + 'modeltranslation/js/force_jquery.js', + 'http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js', + 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.2/jquery-ui.min.js', + 'modeltranslation/js/tabbed_translation_fields.js', + ) + css = { + 'screen': ('modeltranslation/css/tabbed_translation_fields.css',), + } \ No newline at end of file