diff --git a/README.md b/README.md index f543e20..b53d102 100644 --- a/README.md +++ b/README.md @@ -1 +1,3 @@ -# low-carbon-template +# Low-carbon Wagtail template + +A Wagtail website template optimized for energy efficiency and low carbon emissions. Initially built as a headless website with Django REST Framework and Next.js, with deployment as a static site. diff --git a/blog/admin.py b/blog/admin.py deleted file mode 100644 index 8c38f3f..0000000 --- a/blog/admin.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.contrib import admin - -# Register your models here. diff --git a/blog/migrations/0001_initial.py b/blog/migrations/0001_initial.py index b6dae87..0e05df1 100644 --- a/blog/migrations/0001_initial.py +++ b/blog/migrations/0001_initial.py @@ -1,24 +1,17 @@ -# Generated by Django 4.2.13 on 2024-08-21 12:54 +# Generated by Django 5.1 on 2024-09-01 16:48 -from django.db import migrations, models import django.db.models.deletion -import modelcluster.contrib.taggit -import modelcluster.fields -import wagtail.blocks import wagtail.fields -import wagtail.images.blocks +import wagtail_headless_preview.models +from django.db import migrations, models class Migration(migrations.Migration): + initial = True dependencies = [ - ("wagtailimages", "0026_delete_uploadedimage"), - ("wagtailcore", "0093_uploadedfile"), - ( - "taggit", - "0006_rename_taggeditem_content_type_object_id_taggit_tagg_content_8fc721_idx", - ), + ("wagtailcore", "0094_alter_page_locale"), ] operations = [ @@ -55,47 +48,10 @@ class Migration(migrations.Migration): options={ "abstract": False, }, - bases=("wagtailcore.page",), + bases=(wagtail_headless_preview.models.HeadlessMixin, "wagtailcore.page"), ), 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", - ), - ), - ("publication_date", models.DateField(verbose_name="Post date")), - ("introduction", wagtail.fields.RichTextField()), - ( - "body", - wagtail.fields.StreamField( - [ - ("image", wagtail.images.blocks.ImageChooserBlock()), - ("paragraph", wagtail.blocks.RichTextBlock()), - ] - ), - ), - ( - "authors", - modelcluster.fields.ParentalManyToManyField( - blank=True, to="blog.author" - ), - ), - ], - options={ - "abstract": False, - }, - bases=("wagtailcore.page",), - ), - migrations.CreateModel( - name="BlogPageTag", + name="Category", fields=[ ( "id", @@ -106,75 +62,61 @@ class Migration(migrations.Migration): verbose_name="ID", ), ), - ( - "content_object", - modelcluster.fields.ParentalKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="tagged_items", - to="blog.blogpage", - ), - ), - ( - "tag", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="%(app_label)s_%(class)s_items", - to="taggit.tag", - ), - ), + ("name", models.CharField(max_length=255)), ], options={ - "abstract": False, + "verbose_name_plural": "categories", }, ), migrations.CreateModel( - name="BlogPageGalleryImage", + name="BlogPage", fields=[ ( - "id", - models.BigAutoField( + "page_ptr", + models.OneToOneField( auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, primary_key=True, serialize=False, - verbose_name="ID", + to="wagtailcore.page", ), ), + ("publication_date", models.DateField(verbose_name="Post date")), + ("introduction", wagtail.fields.RichTextField()), ( - "sort_order", - models.IntegerField(blank=True, editable=False, null=True), + "body", + wagtail.fields.StreamField( + [("image", 0), ("paragraph", 1)], + block_lookup={ + 0: ("wagtail.images.blocks.ImageChooserBlock", (), {}), + 1: ("wagtail.blocks.RichTextBlock", (), {}), + }, + ), ), - ("caption", models.CharField(blank=True, max_length=250)), ( - "image", + "author", models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, related_name="+", - to="wagtailimages.image", + to="blog.author", ), ), ( - "page", - modelcluster.fields.ParentalKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="gallery_images", - to="blog.blogpage", + "category", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to="blog.category", ), ), ], options={ - "ordering": ["sort_order"], "abstract": False, }, - ), - migrations.AddField( - model_name="blogpage", - name="tags", - field=modelcluster.contrib.taggit.ClusterTaggableManager( - blank=True, - help_text="A comma-separated list of tags.", - through="blog.BlogPageTag", - to="taggit.Tag", - verbose_name="Tags", - ), + bases=(wagtail_headless_preview.models.HeadlessMixin, "wagtailcore.page"), ), ] diff --git a/blog/migrations/0002_category_remove_blogpage_tags_and_more.py b/blog/migrations/0002_category_remove_blogpage_tags_and_more.py deleted file mode 100644 index 89e64ab..0000000 --- a/blog/migrations/0002_category_remove_blogpage_tags_and_more.py +++ /dev/null @@ -1,60 +0,0 @@ -# Generated by Django 4.2.13 on 2024-08-22 17:20 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - dependencies = [ - ("blog", "0001_initial"), - ] - - operations = [ - migrations.CreateModel( - name="Category", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("name", models.CharField(max_length=255)), - ], - options={ - "verbose_name_plural": "categories", - }, - ), - migrations.RemoveField( - model_name="blogpage", - name="tags", - ), - migrations.RemoveField( - model_name="blogpage", - name="authors", - ), - migrations.AddField( - model_name="blogpage", - name="category", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to="blog.category", - ), - ), - migrations.AddField( - model_name="blogpage", - name="authors", - field=models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to="blog.author", - ), - ), - ] diff --git a/blog/models.py b/blog/models.py index 21a94c8..e9c84b9 100644 --- a/blog/models.py +++ b/blog/models.py @@ -1,19 +1,14 @@ -from django import forms from django.db import models - -from modelcluster.fields import ParentalKey, ParentalManyToManyField -from wagtail.models import Page, Orderable +from rest_framework import serializers +from wagtail import blocks +from wagtail.admin.panels import FieldPanel, MultiFieldPanel +from wagtail.api import APIField from wagtail.fields import RichTextField, StreamField -from wagtail.admin.panels import FieldPanel, InlinePanel, MultiFieldPanel +from wagtail.images.blocks import ImageChooserBlock +from wagtail.models import Page from wagtail.search import index -from wagtail import blocks -from modelcluster.contrib.taggit import ClusterTaggableManager -from taggit.models import TaggedItemBase from wagtail.snippets.models import register_snippet -from wagtail.images.blocks import ImageChooserBlock - -from wagtail.api import APIField -from rest_framework import serializers +from wagtail_headless_preview.models import HeadlessMixin @register_snippet @@ -43,40 +38,36 @@ class Meta: verbose_name_plural = "categories" +class AuthorSerializer(serializers.ModelSerializer): + class Meta: + model = Author + fields = ["name"] + + class CategorySerializer(serializers.ModelSerializer): class Meta: model = Category fields = ["name"] -class BlogIndexPage(Page): +class BlogIndexPage(HeadlessMixin, Page): + parent_page_types = ["home.HomePage"] subpage_types = ["blog.BlogPage"] + max_count = 1 -class BlogPageTag(TaggedItemBase): # do it with snnipet - content_object = ParentalKey( - "BlogPage", related_name="tagged_items", on_delete=models.CASCADE - ) - +class BlogPage(HeadlessMixin, Page): + parent_page_types = ["blog.BlogIndexPage"] -class BlogPage(Page): publication_date = models.DateField("Post date") introduction = RichTextField() - authors = models.ForeignKey( + author = models.ForeignKey( "blog.Author", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) - - body = StreamField( - [ - ("image", ImageChooserBlock()), - ("paragraph", blocks.RichTextBlock()), # add embedblock and blockquote - ] - ) - category = models.ForeignKey( "blog.Category", null=True, @@ -84,19 +75,19 @@ class BlogPage(Page): related_name="+", ) - def main_image(self): - gallery_item = self.gallery_images.first() - if gallery_item: - return gallery_item.image - else: - return None + body = StreamField( + [ + ("image", ImageChooserBlock()), + ("paragraph", blocks.RichTextBlock()), + ] + ) api_fields = [ APIField("publication_date"), APIField("introduction"), - APIField("authors"), - APIField("body"), + APIField("author", serializer=AuthorSerializer()), APIField("category", serializer=CategorySerializer()), + APIField("body"), ] search_fields = Page.search_fields + [ @@ -108,29 +99,11 @@ def main_image(self): MultiFieldPanel( [ FieldPanel("publication_date"), - FieldPanel("authors", widget=forms.CheckboxSelectMultiple), + FieldPanel("author"), + FieldPanel("category"), ], heading="Blog information", ), FieldPanel("introduction"), FieldPanel("body"), - FieldPanel("category"), - InlinePanel("gallery_images", label="Gallery images"), - ] - - parent_page_types = ["blog.BlogIndexPage"] - - -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) - - panels = [ - FieldPanel("image"), - FieldPanel("caption"), ] diff --git a/blog/templates/blog/blog_index_page.html b/blog/templates/blog/blog_index_page.html deleted file mode 100644 index 57053a8..0000000 --- a/blog/templates/blog/blog_index_page.html +++ /dev/null @@ -1,13 +0,0 @@ -{% extends "base.html" %} -{% load wagtailcore_tags %} - -{% block content %} -

{{ page.title }}

-
{{ page.introduction|richtext }}
- - {% for post in page.get_children %} -

{{ post.title }}

- {{ post.specific.introduction }} - {{ post.specific.body|richtext }} - {% endfor %} -{% endblock %} diff --git a/blog/templates/blog/blog_page.html b/blog/templates/blog/blog_page.html deleted file mode 100644 index 62927fc..0000000 --- a/blog/templates/blog/blog_page.html +++ /dev/null @@ -1,31 +0,0 @@ -{% extends "base.html" %} -{% load wagtailcore_tags %} - -{% block content %} -

{{ page.blog_title }}

-

{{ page.date }}

-
{{ page.introduction|richtext }}
- - {% with authors=page.authors.all %} - {% if authors %} -

Posted by:

- - {% endif %} - {% endwith %} - - - {% for item in page.gallery_images.all %} -
- {% image item.image fill-320x240 %} -

{{ item.caption }}

-
- {% endfor %} - -

Return to blog

-{% endblock %} diff --git a/blog/tests.py b/blog/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/blog/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/blog/views.py b/blog/views.py deleted file mode 100644 index 91ea44a..0000000 --- a/blog/views.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.shortcuts import render - -# Create your views here. diff --git a/demo/README.md b/demo/README.md new file mode 100644 index 0000000..405a485 --- /dev/null +++ b/demo/README.md @@ -0,0 +1,13 @@ +# Demo site + +Delete this folder when setting up a new site with our template + +## Demo data + +To load the demo data, use: + +To save new demo data, use: + +```bash +./manage.py dumpdata --natural-foreign --indent 2 -e auth.permission -e contenttypes -e wagtailcore.GroupCollectionPermission -e wagtailimages.rendition -e sessions -e wagtailsearch.indexentry -e wagtailsearch.sqliteftsindexentry -e wagtailcore.referenceindex -e wagtailcore.pagesubscription -e wagtail_headless_preview.pagepreview -e wagtailcore.pagelogentry -e wagtailcore.modellogentry > demo/fixtures.json +``` diff --git a/demo/fixtures.json b/demo/fixtures.json new file mode 100644 index 0000000..10af5f6 --- /dev/null +++ b/demo/fixtures.json @@ -0,0 +1,499 @@ +[ + { + "model": "blog.author", + "pk": 1, + "fields": { + "name": "Roberta Johnson" + } + }, + { + "model": "blog.author", + "pk": 2, + "fields": { + "name": "Muddy Waters" + } + }, + { + "model": "blog.author", + "pk": 3, + "fields": { + "name": "Olivia Ava" + } + }, + { + "model": "blog.category", + "pk": 1, + "fields": { + "name": "Sustainability" + } + }, + { + "model": "blog.category", + "pk": 2, + "fields": { + "name": "Accessibility" + } + }, + { + "model": "blog.category", + "pk": 3, + "fields": { + "name": "Django" + } + }, + { + "model": "blog.category", + "pk": 4, + "fields": { + "name": "SEO" + } + }, + { + "model": "blog.category", + "pk": 5, + "fields": { + "name": "Performance" + } + }, + { + "model": "wagtail_headless_preview.pagepreview", + "pk": 1, + "fields": { + "token": "parent_id=1;page_type=home.HomePage:1skmqw:E4dVDUpIjXX2gLVmnAWwzYTV2aZDi9l_IIKyIeqVAo0", + "content_type": ["home", "homepage"], + "content_json": "{\"pk\": null, \"path\": \"00010001\", \"depth\": 2, \"numchild\": 0, \"translation_key\": \"dba11455-ca4f-4432-874c-75c0be2a10aa\", \"locale\": 1, \"latest_revision\": null, \"live\": true, \"has_unpublished_changes\": false, \"first_published_at\": null, \"last_published_at\": null, \"live_revision\": null, \"go_live_at\": null, \"expire_at\": null, \"expired\": false, \"locked\": false, \"locked_at\": null, \"locked_by\": null, \"title\": \"Low-carbon Wagtail template\", \"draft_title\": \"Low-carbon Wagtail template\", \"slug\": \"low-carbon-wagtail-template\", \"content_type\": 32, \"url_path\": \"/low-carbon-wagtail-template/\", \"owner\": null, \"seo_title\": \"\", \"show_in_menus\": false, \"search_description\": \"\", \"latest_revision_created_at\": null, \"alias_of\": null, \"introduction\": \"

A Wagtail website template optimized for energy efficiency and low carbon emissions.

\", \"body\": \"[]\", \"wagtail_admin_comments\": []}", + "created_at": "2024-09-01" + } + }, + { + "model": "wagtailcore.locale", + "pk": 1, + "fields": { + "language_code": "en" + } + }, + { + "model": "wagtailcore.site", + "pk": 2, + "fields": { + "hostname": "localhost", + "port": 3000, + "site_name": "", + "root_page": 3, + "is_default_site": true + } + }, + { + "model": "wagtailcore.collection", + "pk": 1, + "fields": { + "path": "0001", + "depth": 1, + "numchild": 0, + "name": "Root" + } + }, + { + "model": "wagtailcore.workflowpage", + "pk": 1, + "fields": { + "workflow": 1 + } + }, + { + "model": "wagtailcore.workflowtask", + "pk": 1, + "fields": { + "sort_order": 0, + "workflow": 1, + "task": 1 + } + }, + { + "model": "wagtailcore.task", + "pk": 1, + "fields": { + "name": "Moderators approval", + "content_type": ["wagtailcore", "groupapprovaltask"], + "active": true + } + }, + { + "model": "wagtailcore.workflow", + "pk": 1, + "fields": { + "name": "Moderators approval", + "active": true + } + }, + { + "model": "auth.group", + "pk": 1, + "fields": { + "name": "Moderators", + "permissions": [ + ["access_admin", "wagtailadmin", "admin"], + ["add_document", "wagtaildocs", "document"], + ["change_document", "wagtaildocs", "document"], + ["choose_document", "wagtaildocs", "document"], + ["delete_document", "wagtaildocs", "document"], + ["add_image", "wagtailimages", "image"], + ["change_image", "wagtailimages", "image"], + ["choose_image", "wagtailimages", "image"], + ["delete_image", "wagtailimages", "image"] + ] + } + }, + { + "model": "auth.group", + "pk": 2, + "fields": { + "name": "Editors", + "permissions": [ + ["access_admin", "wagtailadmin", "admin"], + ["add_document", "wagtaildocs", "document"], + ["change_document", "wagtaildocs", "document"], + ["choose_document", "wagtaildocs", "document"], + ["delete_document", "wagtaildocs", "document"], + ["add_image", "wagtailimages", "image"], + ["change_image", "wagtailimages", "image"], + ["choose_image", "wagtailimages", "image"], + ["delete_image", "wagtailimages", "image"] + ] + } + }, + { + "model": "auth.user", + "pk": 1, + "fields": { + "password": "pbkdf2_sha256$870000$4dR2xPpUAnm06u1X3ZSvon$ZOBwPrDj5EDGEXRS0pEkmRfwwEKiiVp+zsnqxZcXB4o=", + "last_login": "2024-09-01T00:01:00.097Z", + "is_superuser": true, + "username": "admin", + "first_name": "", + "last_name": "", + "email": "", + "is_staff": true, + "is_active": true, + "date_joined": "2024-09-01T00:01:00.097Z", + "groups": [], + "user_permissions": [] + } + }, + { + "model": "wagtailcore.pagelogentry", + "pk": 1, + "fields": { + "content_type": ["wagtailcore", "page"], + "label": "Welcome to your new Wagtail site!", + "action": "wagtail.delete", + "data": {}, + "timestamp": "2024-09-01T15:49:09.891Z", + "uuid": "aceb84a7-e7fe-4d22-900f-9ed47faffa78", + "user": ["admin"], + "revision": null, + "content_changed": false, + "deleted": true, + "page": 2 + } + }, + { + "model": "wagtailcore.groupapprovaltask", + "pk": 1, + "fields": { + "groups": [["Moderators"]] + } + }, + { + "model": "wagtailcore.grouppagepermission", + "pk": 1, + "fields": { + "group": ["Moderators"], + "page": 1, + "permission": ["add_page", "wagtailcore", "page"] + } + }, + { + "model": "wagtailcore.grouppagepermission", + "pk": 2, + "fields": { + "group": ["Moderators"], + "page": 1, + "permission": ["change_page", "wagtailcore", "page"] + } + }, + { + "model": "wagtailcore.grouppagepermission", + "pk": 3, + "fields": { + "group": ["Moderators"], + "page": 1, + "permission": ["publish_page", "wagtailcore", "page"] + } + }, + { + "model": "wagtailcore.grouppagepermission", + "pk": 4, + "fields": { + "group": ["Editors"], + "page": 1, + "permission": ["add_page", "wagtailcore", "page"] + } + }, + { + "model": "wagtailcore.grouppagepermission", + "pk": 5, + "fields": { + "group": ["Editors"], + "page": 1, + "permission": ["change_page", "wagtailcore", "page"] + } + }, + { + "model": "wagtailcore.grouppagepermission", + "pk": 6, + "fields": { + "group": ["Moderators"], + "page": 1, + "permission": ["lock_page", "wagtailcore", "page"] + } + }, + { + "model": "wagtailcore.grouppagepermission", + "pk": 7, + "fields": { + "group": ["Moderators"], + "page": 1, + "permission": ["unlock_page", "wagtailcore", "page"] + } + }, + { + "model": "wagtailcore.revision", + "pk": 1, + "fields": { + "content_type": ["home", "homepage"], + "base_content_type": ["wagtailcore", "page"], + "object_id": "3", + "created_at": "2024-09-01T15:51:14.327Z", + "user": ["admin"], + "object_str": "Low-carbon Wagtail template", + "content": { + "pk": 3, + "path": "00010001", + "depth": 2, + "numchild": 0, + "translation_key": "b4a6eb7f-6cb4-409a-b90c-b5810b40e962", + "locale": 1, + "latest_revision": null, + "live": true, + "has_unpublished_changes": false, + "first_published_at": null, + "last_published_at": null, + "live_revision": null, + "go_live_at": null, + "expire_at": null, + "expired": false, + "locked": false, + "locked_at": null, + "locked_by": null, + "title": "Low-carbon Wagtail template", + "draft_title": "Low-carbon Wagtail template", + "slug": "home", + "content_type": 32, + "url_path": "/home/", + "owner": 1, + "seo_title": "", + "show_in_menus": false, + "search_description": "", + "latest_revision_created_at": null, + "alias_of": null, + "introduction": "

A Wagtail website template optimized for energy efficiency and low carbon emissions.

", + "body": "[]", + "wagtail_admin_comments": [] + }, + "approved_go_live_at": null + } + }, + { + "model": "wagtailcore.revision", + "pk": 2, + "fields": { + "content_type": ["blog", "blogindexpage"], + "base_content_type": ["wagtailcore", "page"], + "object_id": "4", + "created_at": "2024-09-01T15:51:40.650Z", + "user": ["admin"], + "object_str": "Blog", + "content": { + "pk": 4, + "path": "000100010001", + "depth": 3, + "numchild": 0, + "translation_key": "e36e94e3-5f7d-4dc5-847d-4c1f1422ed97", + "locale": 1, + "latest_revision": null, + "live": true, + "has_unpublished_changes": false, + "first_published_at": null, + "last_published_at": null, + "live_revision": null, + "go_live_at": null, + "expire_at": null, + "expired": false, + "locked": false, + "locked_at": null, + "locked_by": null, + "title": "Blog", + "draft_title": "Blog", + "slug": "blog", + "content_type": 29, + "url_path": "/home/blog/", + "owner": 1, + "seo_title": "", + "show_in_menus": false, + "search_description": "", + "latest_revision_created_at": null, + "alias_of": null, + "wagtail_admin_comments": [] + }, + "approved_go_live_at": null + } + }, + { + "model": "wagtailcore.page", + "pk": 1, + "fields": { + "path": "0001", + "depth": 1, + "numchild": 1, + "translation_key": "a7d82770-40c9-4a4b-af1e-f4839c14473a", + "locale": 1, + "latest_revision": null, + "live": true, + "has_unpublished_changes": false, + "first_published_at": null, + "last_published_at": null, + "live_revision": null, + "go_live_at": null, + "expire_at": null, + "expired": false, + "locked": false, + "locked_at": null, + "locked_by": null, + "title": "Root", + "draft_title": "Root", + "slug": "root", + "content_type": ["wagtailcore", "page"], + "url_path": "/", + "owner": null, + "seo_title": "", + "show_in_menus": false, + "search_description": "", + "latest_revision_created_at": null, + "alias_of": null + } + }, + { + "model": "wagtailcore.page", + "pk": 3, + "fields": { + "path": "00010001", + "depth": 2, + "numchild": 1, + "translation_key": "b4a6eb7f-6cb4-409a-b90c-b5810b40e962", + "locale": 1, + "latest_revision": 1, + "live": true, + "has_unpublished_changes": false, + "first_published_at": "2024-09-01T15:51:14.361Z", + "last_published_at": "2024-09-01T15:51:14.361Z", + "live_revision": 1, + "go_live_at": null, + "expire_at": null, + "expired": false, + "locked": false, + "locked_at": null, + "locked_by": null, + "title": "Low-carbon Wagtail template", + "draft_title": "Low-carbon Wagtail template", + "slug": "home", + "content_type": ["home", "homepage"], + "url_path": "/home/", + "owner": ["admin"], + "seo_title": "", + "show_in_menus": false, + "search_description": "", + "latest_revision_created_at": "2024-09-01T15:51:14.327Z", + "alias_of": null + } + }, + { + "model": "wagtailcore.page", + "pk": 4, + "fields": { + "path": "000100010001", + "depth": 3, + "numchild": 0, + "translation_key": "e36e94e3-5f7d-4dc5-847d-4c1f1422ed97", + "locale": 1, + "latest_revision": 2, + "live": true, + "has_unpublished_changes": false, + "first_published_at": "2024-09-01T15:51:40.680Z", + "last_published_at": "2024-09-01T15:51:40.680Z", + "live_revision": 2, + "go_live_at": null, + "expire_at": null, + "expired": false, + "locked": false, + "locked_at": null, + "locked_by": null, + "title": "Blog", + "draft_title": "Blog", + "slug": "blog", + "content_type": ["blog", "blogindexpage"], + "url_path": "/home/blog/", + "owner": ["admin"], + "seo_title": "", + "show_in_menus": false, + "search_description": "", + "latest_revision_created_at": "2024-09-01T15:51:40.650Z", + "alias_of": null + } + }, + + { + "model": "wagtailusers.userprofile", + "pk": 1, + "fields": { + "user": ["admin"], + "submitted_notifications": true, + "approved_notifications": true, + "rejected_notifications": true, + "updated_comments_notifications": true, + "preferred_language": "", + "current_time_zone": "", + "avatar": "", + "dismissibles": { + "help": true, + "whats-new-in-wagtail-6.2": true, + "editor-guide": true + }, + "theme": "system", + "density": "default" + } + }, + { + "model": "home.homepage", + "pk": 3, + "fields": { + "introduction": "

A Wagtail website template optimized for energy efficiency and low carbon emissions.

", + "body": "[]" + } + }, + { + "model": "blog.blogindexpage", + "pk": 4, + "fields": {} + } +] diff --git a/home/migrations/0001_initial.py b/home/migrations/0001_initial.py index 27146c6..8da48c0 100644 --- a/home/migrations/0001_initial.py +++ b/home/migrations/0001_initial.py @@ -1,9 +1,17 @@ +# Generated by Django 5.1 on 2024-09-01 15:34 + +import django.db.models.deletion +import wagtail.fields +import wagtail_headless_preview.models from django.db import migrations, models class Migration(migrations.Migration): + + initial = True + dependencies = [ - ("wagtailcore", "0040_page_draft_title"), + ("wagtailcore", "0094_alter_page_locale"), ] operations = [ @@ -13,18 +21,50 @@ class Migration(migrations.Migration): ( "page_ptr", models.OneToOneField( - on_delete=models.CASCADE, - parent_link=True, auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, primary_key=True, serialize=False, - to="wagtailcore.Page", + to="wagtailcore.page", + ), + ), + ("introduction", wagtail.fields.RichTextField()), + ( + "body", + wagtail.fields.StreamField( + [("section", 5)], + blank=True, + block_lookup={ + 0: ( + "wagtail.blocks.CharBlock", + (), + {"form_classname": "title"}, + ), + 1: ("wagtail.blocks.RichTextBlock", (), {}), + 2: ("wagtail.images.blocks.ImageChooserBlock", (), {}), + 3: ("wagtail.blocks.PageChooserBlock", (), {}), + 4: ("wagtail.blocks.CharBlock", (), {}), + 5: ( + "wagtail.blocks.StructBlock", + [ + [ + ("heading", 0), + ("description", 1), + ("image", 2), + ("link", 3), + ("link_text", 4), + ] + ], + {}, + ), + }, ), ), ], options={ "abstract": False, }, - bases=("wagtailcore.page",), + bases=(wagtail_headless_preview.models.HeadlessMixin, "wagtailcore.page"), ), ] diff --git a/home/migrations/0002_create_homepage.py b/home/migrations/0002_create_homepage.py deleted file mode 100644 index a8586fb..0000000 --- a/home/migrations/0002_create_homepage.py +++ /dev/null @@ -1,60 +0,0 @@ -from django.db import migrations - - -def create_homepage(apps, schema_editor): - # Get models - ContentType = apps.get_model("contenttypes.ContentType") - Page = apps.get_model("wagtailcore.Page") - Site = apps.get_model("wagtailcore.Site") - HomePage = apps.get_model("home.HomePage") - - # Delete the default homepage - # If migration is run multiple times, it may have already been deleted - Page.objects.filter(id=2).delete() - - # Create content type for homepage model - homepage_content_type, __ = ContentType.objects.get_or_create( - model="homepage", app_label="home" - ) - - # Create a new homepage - homepage = HomePage.objects.create( - title="Home", - draft_title="Home", - slug="home", - content_type=homepage_content_type, - path="00010001", - depth=2, - numchild=0, - url_path="/home/", - ) - - # Create a site with the new homepage set as the root - Site.objects.create(hostname="localhost", root_page=homepage, is_default_site=True) - - -def remove_homepage(apps, schema_editor): - # Get models - ContentType = apps.get_model("contenttypes.ContentType") - HomePage = apps.get_model("home.HomePage") - - # Delete the default homepage - # Page and Site objects CASCADE - HomePage.objects.filter(slug="home", depth=2).delete() - - # Delete content type for homepage model - ContentType.objects.filter(model="homepage", app_label="home").delete() - - -class Migration(migrations.Migration): - run_before = [ - ("wagtailcore", "0053_locale_model"), - ] - - dependencies = [ - ("home", "0001_initial"), - ] - - operations = [ - migrations.RunPython(create_homepage, remove_homepage), - ] diff --git a/home/migrations/0003_homepage_heading.py b/home/migrations/0003_homepage_heading.py deleted file mode 100644 index 5b4b310..0000000 --- a/home/migrations/0003_homepage_heading.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 4.2.13 on 2024-08-21 03:32 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("home", "0002_create_homepage"), - ] - - operations = [ - migrations.AddField( - model_name="homepage", - name="heading", - field=models.CharField(default="Sustainable Development", max_length=255), - ), - ] diff --git a/home/migrations/0004_homepage_introduction.py b/home/migrations/0004_homepage_introduction.py deleted file mode 100644 index 5c93b60..0000000 --- a/home/migrations/0004_homepage_introduction.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.2.13 on 2024-08-21 03:42 - -from django.db import migrations -import wagtail.fields - - -class Migration(migrations.Migration): - dependencies = [ - ("home", "0003_homepage_heading"), - ] - - operations = [ - migrations.AddField( - model_name="homepage", - name="introduction", - field=wagtail.fields.RichTextField(blank=True), - ), - ] diff --git a/home/migrations/0005_remove_homepage_heading_alter_homepage_introduction.py b/home/migrations/0005_remove_homepage_heading_alter_homepage_introduction.py deleted file mode 100644 index 5cfccf4..0000000 --- a/home/migrations/0005_remove_homepage_heading_alter_homepage_introduction.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 4.2.13 on 2024-08-22 17:20 - -from django.db import migrations -import wagtail.fields - - -class Migration(migrations.Migration): - dependencies = [ - ("home", "0004_homepage_introduction"), - ] - - operations = [ - migrations.RemoveField( - model_name="homepage", - name="heading", - ), - migrations.AlterField( - model_name="homepage", - name="introduction", - field=wagtail.fields.RichTextField(), - ), - ] diff --git a/home/migrations/0006_homepage_body.py b/home/migrations/0006_homepage_body.py deleted file mode 100644 index 7d6028f..0000000 --- a/home/migrations/0006_homepage_body.py +++ /dev/null @@ -1,29 +0,0 @@ -# Generated by Django 4.2.13 on 2024-08-23 12:37 - -from django.db import migrations -import wagtail.blocks -import wagtail.fields -import wagtail.images.blocks - - -class Migration(migrations.Migration): - dependencies = [ - ("home", "0005_remove_homepage_heading_alter_homepage_introduction"), - ] - - operations = [ - migrations.AddField( - model_name="homepage", - name="body", - field=wagtail.fields.StreamField( - [ - ("heading", wagtail.blocks.CharBlock(form_classname="title")), - ("description", wagtail.blocks.RichTextBlock()), - ("image", wagtail.images.blocks.ImageChooserBlock()), - ("link", wagtail.blocks.PageChooserBlock()), - ("link_text", wagtail.blocks.CharBlock()), - ], - blank=True, - ), - ), - ] diff --git a/home/models.py b/home/models.py index 6ecff7c..e1f94ca 100644 --- a/home/models.py +++ b/home/models.py @@ -1,26 +1,32 @@ -from django.db import models - -from wagtail.images.models import Image, AbstractImage, AbstractRendition -from wagtail.models import Page -from wagtail.fields import RichTextField, StreamField +from wagtail import blocks from wagtail.admin.panels import FieldPanel +from wagtail.api import APIField +from wagtail.blocks import PageChooserBlock +from wagtail.fields import RichTextField, StreamField +from wagtail.images.blocks import ImageChooserBlock +from wagtail.models import Page from wagtail.search import index +from wagtail_headless_preview.models import HeadlessMixin -from wagtail import blocks -from wagtail.images.blocks import ImageChooserBlock -from wagtail.blocks import PageChooserBlock -from wagtail.api import APIField +class HomePage(HeadlessMixin, Page): + max_count = 1 -class HomePage(Page): introduction = RichTextField() body = StreamField( [ - ("heading", blocks.CharBlock(form_classname="title")), - ("description", blocks.RichTextBlock()), - ("image", ImageChooserBlock()), - ("link", PageChooserBlock()), - ("link_text", blocks.CharBlock()), + ( + "section", + blocks.StructBlock( + [ + ("heading", blocks.CharBlock(form_classname="title")), + ("description", blocks.RichTextBlock()), + ("image", ImageChooserBlock()), + ("link", PageChooserBlock()), + ("link_text", blocks.CharBlock()), + ] + ), + ), ], blank=True, ) diff --git a/home/static/css/welcome_page.css b/home/static/css/welcome_page.css deleted file mode 100644 index bad2933..0000000 --- a/home/static/css/welcome_page.css +++ /dev/null @@ -1,184 +0,0 @@ -html { - box-sizing: border-box; -} - -*, -*:before, -*:after { - box-sizing: inherit; -} - -body { - max-width: 960px; - min-height: 100vh; - margin: 0 auto; - padding: 0 15px; - color: #231f20; - font-family: 'Helvetica Neue', 'Segoe UI', Arial, sans-serif; - line-height: 1.25; -} - -a { - background-color: transparent; - color: #308282; - text-decoration: underline; -} - -a:hover { - color: #ea1b10; -} - -h1, -h2, -h3, -h4, -h5, -p, -ul { - padding: 0; - margin: 0; - font-weight: 400; -} - -svg:not(:root) { - overflow: hidden; -} - -.header { - display: flex; - justify-content: space-between; - align-items: center; - padding-top: 20px; - padding-bottom: 10px; - border-bottom: 1px solid #e6e6e6; -} - -.logo { - width: 150px; - margin-inline-end: 20px; -} - -.logo a { - display: block; -} - -.figure-logo { - max-width: 150px; - max-height: 55.1px; -} - -.release-notes { - font-size: 14px; -} - -.main { - padding: 40px 0; - margin: 0 auto; - text-align: center; -} - -.figure-space { - max-width: 265px; -} - -@keyframes pos { - 0%, 100% { - transform: rotate(-6deg); - } - 50% { - transform: rotate(6deg); - } -} - -.egg { - fill: #43b1b0; - animation: pos 3s ease infinite; - transform: translateY(50px); - transform-origin: 50% 80%; -} - -.main-text { - max-width: 400px; - margin: 5px auto; -} - -.main-text h1 { - font-size: 22px; -} - -.main-text p { - margin: 15px auto 0; -} - -.footer { - display: flex; - flex-wrap: wrap; - justify-content: space-between; - border-top: 1px solid #e6e6e6; - padding: 10px; -} - -.option { - display: block; - padding: 10px 10px 10px 34px; - position: relative; - text-decoration: none; -} - -.option svg { - width: 24px; - height: 24px; - fill: gray; - border: 1px solid #d9d9d9; - padding: 5px; - border-radius: 100%; - top: 10px; - inset-inline-start: 0; - position: absolute; -} - -.option h2 { - font-size: 19px; - text-decoration: underline; -} - -.option p { - padding-top: 3px; - color: #231f20; - font-size: 15px; - font-weight: 300; -} - -@media (max-width: 996px) { - body { - max-width: 780px; - } -} - -@media (max-width: 767px) { - .option { - flex: 0 0 50%; - } -} - -@media (max-width: 599px) { - .main { - padding: 20px 0; - } - - .figure-space { - max-width: 200px; - } - - .footer { - display: block; - width: 300px; - margin: 0 auto; - } -} - -@media (max-width: 360px) { - .header-link { - max-width: 100px; - } -} diff --git a/home/templates/home/home_page.html b/home/templates/home/home_page.html deleted file mode 100644 index 525e397..0000000 --- a/home/templates/home/home_page.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends "base.html" %} -{% load wagtailcore_tags %} - -{% block content %} -

{{ page.heading }}

-
{{ page.introduction|richtext }}
-{% endblock %} \ No newline at end of file diff --git a/home/templates/home/welcome_page.html b/home/templates/home/welcome_page.html deleted file mode 100644 index dcacaf3..0000000 --- a/home/templates/home/welcome_page.html +++ /dev/null @@ -1,52 +0,0 @@ -{% load i18n wagtailcore_tags %} - -
- - -
-
-
- -
-
-

{% trans "Welcome to your new Wagtail site!" %}

-

{% trans 'Please feel free to join our community on Slack, or get started with one of the links below.' %}

-
-
- diff --git a/sustainablesite/settings/base.py b/sustainablesite/settings/base.py index 9e28802..ff91edb 100644 --- a/sustainablesite/settings/base.py +++ b/sustainablesite/settings/base.py @@ -26,9 +26,9 @@ INSTALLED_APPS = [ "blog", "home", - # "corsheaders", "rest_framework", "wagtail.api.v2", + "wagtail_headless_preview", "wagtail.contrib.forms", "wagtail.contrib.redirects", "wagtail.embeds",