diff --git a/artel/artel/settings/__pycache__/base.cpython-311.pyc b/artel/artel/settings/__pycache__/base.cpython-311.pyc index 8e092d9..140581b 100644 Binary files a/artel/artel/settings/__pycache__/base.cpython-311.pyc and b/artel/artel/settings/__pycache__/base.cpython-311.pyc differ diff --git a/artel/artel/settings/base.py b/artel/artel/settings/base.py index f8add95..8663caf 100644 --- a/artel/artel/settings/base.py +++ b/artel/artel/settings/base.py @@ -25,7 +25,8 @@ BASE_DIR = os.path.dirname(PROJECT_DIR) INSTALLED_APPS = [ "home", - "exhibitions", + "store", + "blog", "search", "wagtail.contrib.forms", "wagtail.contrib.redirects", @@ -37,7 +38,9 @@ INSTALLED_APPS = [ "wagtail.images", "wagtail.search", "wagtail.admin", + 'wagtail.contrib.modeladmin', "wagtail", + "wagtailmenus", "modelcluster", "taggit", "django.contrib.admin", @@ -74,6 +77,7 @@ TEMPLATES = [ "django.template.context_processors.request", "django.contrib.auth.context_processors.auth", "django.contrib.messages.context_processors.messages", + 'wagtailmenus.context_processors.wagtailmenus', ], }, }, diff --git a/artel/artel/templates/base.html b/artel/artel/templates/base.html index 28f6d95..1b32201 100644 --- a/artel/artel/templates/base.html +++ b/artel/artel/templates/base.html @@ -1,4 +1,5 @@ {% load static wagtailcore_tags wagtailuserbar %} +{% load menu_tags %} @@ -33,8 +34,14 @@ {% wagtailuserbar %} - - {% block content %}{% endblock %} +
+
+ {% main_menu template="menu/custom_main_menu.html" %} +
+
+ {% block content %}{% endblock %} +
+
{# Global javascript #} diff --git a/artel/artel/templates/menu/custom_main_menu.html b/artel/artel/templates/menu/custom_main_menu.html new file mode 100644 index 0000000..939c5c8 --- /dev/null +++ b/artel/artel/templates/menu/custom_main_menu.html @@ -0,0 +1,14 @@ + \ No newline at end of file diff --git a/artel/exhibitions/__init__.py b/artel/blog/__init__.py similarity index 100% rename from artel/exhibitions/__init__.py rename to artel/blog/__init__.py diff --git a/artel/exhibitions/admin.py b/artel/blog/admin.py similarity index 100% rename from artel/exhibitions/admin.py rename to artel/blog/admin.py diff --git a/artel/exhibitions/apps.py b/artel/blog/apps.py similarity index 60% rename from artel/exhibitions/apps.py rename to artel/blog/apps.py index b8d3471..94788a5 100644 --- a/artel/exhibitions/apps.py +++ b/artel/blog/apps.py @@ -1,6 +1,6 @@ from django.apps import AppConfig -class ExhibitionsConfig(AppConfig): +class BlogConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' - name = 'exhibitions' + name = 'blog' diff --git a/artel/blog/migrations/0001_initial.py b/artel/blog/migrations/0001_initial.py new file mode 100644 index 0000000..1b511ac --- /dev/null +++ b/artel/blog/migrations/0001_initial.py @@ -0,0 +1,48 @@ +# Generated by Django 4.1.8 on 2023-04-28 20:41 + +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion +import modelcluster.fields +import wagtail.fields + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('wagtailcore', '0083_workflowcontenttype'), + ('wagtailimages', '0025_alter_image_file_alter_rendition_file'), + ] + + operations = [ + migrations.CreateModel( + name='BlogPage', + fields=[ + ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')), + ('create_date', models.DateField(auto_now_add=True)), + ('edit_date', models.DateField(auto_now=True)), + ('body', wagtail.fields.RichTextField()), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + migrations.CreateModel( + name='BlogPageGalleryImage', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('sort_order', models.IntegerField(blank=True, editable=False, null=True)), + ('caption', models.CharField(blank=True, max_length=250)), + ('order', models.IntegerField(validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000)])), + ('image', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to='wagtailimages.image')), + ('page', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='gallery_images', to='blog.blogpage')), + ], + options={ + 'ordering': ['sort_order'], + 'abstract': False, + }, + ), + ] diff --git a/artel/exhibitions/migrations/__init__.py b/artel/blog/migrations/__init__.py similarity index 100% rename from artel/exhibitions/migrations/__init__.py rename to artel/blog/migrations/__init__.py diff --git a/artel/blog/models.py b/artel/blog/models.py new file mode 100644 index 0000000..7ab6502 --- /dev/null +++ b/artel/blog/models.py @@ -0,0 +1,47 @@ +from django.db import models +from django.core.validators import ( + MinValueValidator, + MaxValueValidator +) + +from wagtail.models import Page, Orderable +from wagtail.fields import RichTextField +from wagtail.admin.panels import ( + FieldPanel, + InlinePanel +) +from wagtail.search import index +from modelcluster.fields import ParentalKey + + +class BlogPage(Page): + create_date = models.DateField(auto_now_add=True) + edit_date = models.DateField(auto_now=True) + + body = RichTextField() + + content_panels = Page.content_panels + [ + FieldPanel("body"), + InlinePanel("gallery_images") + ] + + +class BlogPageGalleryImage(Orderable): + page = ParentalKey(BlogPage, on_delete=models.CASCADE, related_name='gallery_images') + image = models.ForeignKey( + 'wagtailimages.Image', on_delete=models.CASCADE, related_name='+' + ) + caption = models.CharField(blank=True, max_length=250) + + order = models.IntegerField( + validators=[ + MinValueValidator(0), + MaxValueValidator(1000) + ] + ) + + panels = [ + FieldPanel('order'), + FieldPanel('image'), + FieldPanel('caption'), + ] diff --git a/artel/blog/templates/blog/blog_page.html b/artel/blog/templates/blog/blog_page.html new file mode 100644 index 0000000..89d786b --- /dev/null +++ b/artel/blog/templates/blog/blog_page.html @@ -0,0 +1,18 @@ +{% extends "base.html" %} + +{% load wagtailcore_tags wagtailimages_tags %} + +{% block content %} +

{{ page.title }}

+

{{ page.date }}

+ +
{{ page.body|richtext }}
+ + {% for item in page.gallery_images.all %} +
+ {% image item.image fill-320x240 %} +

{{ item.caption }}

+
+ {% endfor %} + +{% endblock %} diff --git a/artel/exhibitions/tests.py b/artel/blog/tests.py similarity index 100% rename from artel/exhibitions/tests.py rename to artel/blog/tests.py diff --git a/artel/exhibitions/views.py b/artel/blog/views.py similarity index 100% rename from artel/exhibitions/views.py rename to artel/blog/views.py diff --git a/artel/exhibitions/__pycache__/__init__.cpython-311.pyc b/artel/exhibitions/__pycache__/__init__.cpython-311.pyc deleted file mode 100644 index 1082b21..0000000 Binary files a/artel/exhibitions/__pycache__/__init__.cpython-311.pyc and /dev/null differ diff --git a/artel/exhibitions/__pycache__/admin.cpython-311.pyc b/artel/exhibitions/__pycache__/admin.cpython-311.pyc deleted file mode 100644 index 889cc9c..0000000 Binary files a/artel/exhibitions/__pycache__/admin.cpython-311.pyc and /dev/null differ diff --git a/artel/exhibitions/__pycache__/apps.cpython-311.pyc b/artel/exhibitions/__pycache__/apps.cpython-311.pyc deleted file mode 100644 index e261fd6..0000000 Binary files a/artel/exhibitions/__pycache__/apps.cpython-311.pyc and /dev/null differ diff --git a/artel/exhibitions/__pycache__/models.cpython-311.pyc b/artel/exhibitions/__pycache__/models.cpython-311.pyc deleted file mode 100644 index 452096e..0000000 Binary files a/artel/exhibitions/__pycache__/models.cpython-311.pyc and /dev/null differ diff --git a/artel/exhibitions/migrations/__pycache__/0001_initial.cpython-311.pyc b/artel/exhibitions/migrations/__pycache__/0001_initial.cpython-311.pyc deleted file mode 100644 index 53449be..0000000 Binary files a/artel/exhibitions/migrations/__pycache__/0001_initial.cpython-311.pyc and /dev/null differ diff --git a/artel/exhibitions/migrations/__pycache__/__init__.cpython-311.pyc b/artel/exhibitions/migrations/__pycache__/__init__.cpython-311.pyc deleted file mode 100644 index 9ce2682..0000000 Binary files a/artel/exhibitions/migrations/__pycache__/__init__.cpython-311.pyc and /dev/null differ diff --git a/artel/exhibitions/models.py b/artel/exhibitions/models.py deleted file mode 100644 index 3bf1e43..0000000 --- a/artel/exhibitions/models.py +++ /dev/null @@ -1,44 +0,0 @@ -from django.db import models -from wagtail.models import ( - Page, - Orderable -) -from wagtail import fields -from wagtail.admin.panels import ( - FieldPanel, - InlinePanel -) -from modelcluster.fields import ParentalKey - - -class ExhibitionIndexPage(Page): - intro = fields.RichTextField(blank=True) - - content_panels = Page.content_panels + [ - FieldPanel('intro') - ] - - -class ExhibitionPage(Page): - exhibition_desc = fields.RichTextField(blank=True) - - content_panels = Page.content_panels + [ - FieldPanel('exhibition_desc'), - InlinePanel('exhibits', label="Exhibits") - ] - - -class Exhibit(Orderable): - page = ParentalKey(ExhibitionPage, on_delete=models.CASCADE, related_name='exhibits') - image = models.ForeignKey( - 'wagtailimages.Image', on_delete=models.CASCADE, related_name='+' - ) - title = models.CharField(max_length=250) - slug = models.SlugField() - exhibit_description = models.TextField(blank=True, default="") - - panels = [ - FieldPanel('image'), - FieldPanel('caption'), - FieldPanel("exhibit_description") - ] diff --git a/artel/exhibitions/templates/exhibitions/exhibition_index_page.html b/artel/exhibitions/templates/exhibitions/exhibition_index_page.html deleted file mode 100644 index d58f2ff..0000000 --- a/artel/exhibitions/templates/exhibitions/exhibition_index_page.html +++ /dev/null @@ -1,17 +0,0 @@ -{% extends "base.html" %} - -{% load wagtailcore_tags %} - -{% block body_class %}template-blogindexpage{% endblock %} - -{% block content %} -

{{ page.title }}

- -
{{ page.intro|richtext }}
- - {% for exhibition in page.get_children %} -

{{ exhibition.title }}

- {{ exhibition.specific.exhibition_desc }} - {% endfor %} - -{% endblock %} \ No newline at end of file diff --git a/artel/exhibitions/templates/exhibitions/exhibition_page.html b/artel/exhibitions/templates/exhibitions/exhibition_page.html deleted file mode 100644 index 318c5c4..0000000 --- a/artel/exhibitions/templates/exhibitions/exhibition_page.html +++ /dev/null @@ -1,20 +0,0 @@ -{% extends "base.html" %} - -{% load wagtailcore_tags wagtailimages_tags %} - -{% block body_class %}template-blogpage{% endblock %} - -{% block content %} -

{{ page.title }}

-
- {% for item in page.exhibits.all %} -
- {% image item.image max-320x200 %} -

{{ item.caption }}

-
- {% endfor %} -
- -
Return to blog
- -{% endblock %} \ No newline at end of file diff --git a/artel/home/templates/home/home_page.html b/artel/home/templates/home/home_page.html index 85c0021..c923639 100644 --- a/artel/home/templates/home/home_page.html +++ b/artel/home/templates/home/home_page.html @@ -5,5 +5,7 @@ {% block body_class %}template-homepage{% endblock %} {% block content %} - {{ page.body|richtext }} +
+ {{ page.body|richtext }} +
{% endblock %} \ No newline at end of file diff --git a/artel/requirements.txt b/artel/requirements.txt index f0b8e40..adb50bf 100644 --- a/artel/requirements.txt +++ b/artel/requirements.txt @@ -1,2 +1,3 @@ Django>=4.1,<4.2 wagtail>=4.2,<4.3 +wagtailmenus>=3.15, <=3.1.7 diff --git a/artel/store/admin.py b/artel/store/admin.py index 8c38f3f..ffe0108 100644 --- a/artel/store/admin.py +++ b/artel/store/admin.py @@ -1,3 +1,47 @@ -from django.contrib import admin +from django.forms import fields -# Register your models here. +from wagtail.contrib.modeladmin.options import ( + ModelAdmin, + ModelAdminGroup, + modeladmin_register +) +from wagtail.admin.forms.models import WagtailAdminModelForm + +from store import models + + +class ProductConfigAdmin(ModelAdmin): + model = models.ProductConfig + list_display = ("author__name", "color", "price") + search_fields = ("author__name", "color", "price") + + +class ProductTemplateAdmin(ModelAdmin): + model = models.ProductTemplate + list_display = ("title", ) + + +class ProductAdminForm(WagtailAdminModelForm): + + template_title = fields.CharField() + template_code = fields.CharField() + template_description = fields.CharField() + + class Meta: + fields = ("template_title", "template_code", "template_description") + model = models.Product + + +class ProductAdmin(ModelAdmin): + model = models.Product + form = ProductAdminForm + + +class StoreAdminGroup(ModelAdminGroup): + menu_label = "Store" + menu_icon = 'folder-open-inverse' + menu_order = 200 + items = (ProductConfigAdmin, ProductTemplateAdmin, ProductAdmin) + + +modeladmin_register(StoreAdminGroup) diff --git a/artel/store/migrations/0001_initial.py b/artel/store/migrations/0001_initial.py new file mode 100644 index 0000000..046c795 --- /dev/null +++ b/artel/store/migrations/0001_initial.py @@ -0,0 +1,57 @@ +# Generated by Django 4.1.8 on 2023-04-25 22:22 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='ProductAuthor', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ], + ), + migrations.CreateModel( + name='ProductTemplate', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=255)), + ('code', models.CharField(max_length=255)), + ('description', models.TextField()), + ], + ), + migrations.CreateModel( + name='ProductImage', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('image', models.ImageField(upload_to='')), + ('template', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='images', to='store.producttemplate')), + ], + ), + migrations.CreateModel( + name='ProductConfig', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('color', models.CharField(max_length=255)), + ('size', models.CharField(max_length=50)), + ('price', models.FloatField()), + ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='store.productauthor')), + ], + ), + migrations.CreateModel( + name='Product', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('config', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='store.productconfig')), + ('template', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='store.producttemplate')), + ], + ), + ] diff --git a/artel/store/models.py b/artel/store/models.py index cf5be90..8851557 100644 --- a/artel/store/models.py +++ b/artel/store/models.py @@ -1,16 +1,34 @@ from django.db import models -class Product(models.Model): - template = models.ForeignKey("exhibitions.Exhibit", on_delete=models.CASCADE) - - -class ProductSource(models.Model): +class ProductAuthor(models.Model): name = models.CharField(max_length=255) + # TODO - author contact info? maybe foreignkey with user + +class ProductTemplate(models.Model): + title = models.CharField(max_length=255) + code = models.CharField(max_length=255) + description = models.TextField() + + def get_images(self): + return self.images.objects.all().values_list("image") + + +class ProductImage(models.Model): + template = models.ForeignKey( + ProductTemplate, on_delete=models.CASCADE, related_name="images" + ) + image = models.ImageField() class ProductConfig(models.Model): - source = models.ForeignKey(ProductSource, on_delete=models.CASCADE) + author = models.ForeignKey(ProductAuthor, on_delete=models.CASCADE) color = models.CharField(max_length=255) - + size = models.CharField(max_length=50) price = models.FloatField() + + +class Product(models.Model): + template = models.ForeignKey(ProductTemplate, on_delete=models.CASCADE) + config = models.ForeignKey(ProductConfig, on_delete=models.CASCADE) +