iT邦幫忙

2024 iThome 鐵人賽

DAY 16
0

創建一個作品集頁面
作品集頁面是很好表現在個人 blog 上的,在 Wagtail 中,我們會使用 StreamField 在你的作品集網站上添加一個作品集頁面。

首先解釋 StreamField。
StreamField 是一個功能,它旨在平衡開發者對結構化數據的需求和內容創建者在創建和組織內容時對編輯靈活性的需求。

在傳統的內容管理系統中,通常需要在結構化內容和賦予編輯者創建靈活佈局的自由之間做出妥協。通常,富文本字段被用來給內容創建者他們需要的工具來製作靈活多變的內容。富文本字段可以提供一個所見即所得的編輯器來進行格式化。然而,富文本字段有其限制。

富文本字段的一個限制是丟失語義價值。內容中的語義價值表示由內容的結構和標記傳達的潛在意義或信息。當內容缺乏語義價值時,就更難確定其預期的意義或目的。例如,當編輯者使用富文本字段來設計文本或插入多媒體時,內容可能不會被語義標記為這樣。

因此,StreamField 為編輯者提供了更大的靈活性,並解決了富文本字段的限制。StreamField 是一種多功能的內容管理解決方案,將內容視為一系列的塊。每個塊代表不同的內容類型,如段落、圖像和地圖。編輯者可以排列和自定義這些塊來創建復雜和靈活的佈局。此外,StreamField 還可以捕獲不同內容類型的語義意義。

增加新的 app - protofolio

首先,通過運行以下命令為你的作品集網站添加一個新的應用:

python manage.py startapp portfolio

然後在 mysite/settings/base.py 文件中的 INSTALLED_APPS 列表中添加 "portfolio" 來裝上的新作品集應用到網站。

settings/base.py 看起來會像這樣。


INSTALLED_APPS = [
    "portfolio", # 要將 portfolio 加入
    "base",
    "blog",
    "home",
    "search",
    "wagtail.contrib.forms",
    "wagtail.contrib.redirects",
    "wagtail.embeds",
    "wagtail.sites",
    "wagtail.users",
    "wagtail.snippets",
    "wagtail.documents",
    "wagtail.images",
    "wagtail.search",
    "wagtail.admin",
    "wagtail",
    "modelcluster",
    "taggit",
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "wagtail.contrib.settings",
]

現在創建一個 base/blocks.py 文件並向其中添加以下 code:

from wagtail.blocks import (
    CharBlock,
    ChoiceBlock,
    RichTextBlock,
    StreamBlock,
    StructBlock,
)
from wagtail.embeds.blocks import EmbedBlock
from wagtail.images.blocks import ImageChooserBlock

class ImageBlock(StructBlock):
    image = ImageChooserBlock(required=True)
    caption = CharBlock(required=False)
    attribution = CharBlock(required=False)

    class Meta:
        icon = "image"
        template = "base/blocks/image_block.html"

class HeadingBlock(StructBlock):
    heading_text = CharBlock(classname="title", required=True)
    size = ChoiceBlock(
        choices=[
            ("", "Select a heading size"),
            ("h2", "H2"),
            ("h3", "H3"),
            ("h4", "H4"),
        ],
        blank=True,
        required=False,
    )

    class Meta:
        icon = "title"
        template = "base/blocks/heading_block.html"

class BaseStreamBlock(StreamBlock):
    heading_block = HeadingBlock()
    paragraph_block = RichTextBlock(icon="pilcrow")
    image_block = ImageBlock()
    embed_block = EmbedBlock(
        help_text="Insert a URL to embed. For example, https://www.youtube.com/watch?v=SGJFWirQ3ks",
        icon="media",
    )

在前面的代碼中,你為你的通用應用創建了可重用的 Wagtail 自定義塊,用於不同的內容類型。你可以在網站的任何位置按任何順序使用這些塊。讓我們更仔細地看看這些塊中的每一個。

首先,ImageBlock 是一個塊,編輯者可以使用它在 StreamField 部分添加圖像。

class ImageBlock(StructBlock):
    image = ImageChooserBlock(required=True)
    caption = CharBlock(required=False)
    attribution = CharBlock(required=False)
    class Meta:
        icon = "image"
        template = "base/blocks/image_block.html"

在前面的代碼中,你為通用應用創建了適用於不同內容類型的可重用 Wagtail 自定義塊。你可以在你的網站上以任何順序使用這些塊。讓我們更仔細地看看這些塊中的每一個。

首先,ImageBlock 是一個結構塊,編輯者可以使用它在 StreamField 部分添加圖像。

class ImageBlock(StructBlock):
    image = ImageChooserBlock(required=True)
    caption = CharBlock(required=False)
    attribution = CharBlock(required=False)
    class Meta:
        icon = "image"
        template = "base/blocks/image_block.html"

ImageBlock 繼承自 StructBlock。使用 StructBlock,你可以將幾個子塊組合在一個父塊下。你的 ImageBlock 有三個子塊。第一個子塊,圖像,使用 ImageChooserBlock 域塊類型。使用 ImageChooserBlock,編輯者可以選擇現有圖像或上傳新圖像。它的 required 參數為 true,這意味著你必須為塊提供圖像才能工作。caption 和 attribution 子塊使用 CharBlock 域塊類型,它提供單行文本輸入以添加圖像的標題和歸屬。你的標題和歸屬子塊的 required 屬性設置為 false。這意味著如果你想,你可以在管理介面中將它們留空。

就像 ImageBlock 一樣,你的 HeadingBlock 也繼承自 StructBlock。它有兩個子塊。讓我們來看看這些。

class HeadingBlock(StructBlock):
    heading_text = CharBlock(classname="title", required=True)
    size = ChoiceBlock(
        choices=[
            ("", "Select a heading size"),
            ("h2", "H2"),
            ("h3", "H3"),
            ("h4", "H4"),
        ],
        blank=True,
        required=False,
    )
    class Meta:
        icon = "title"
        template = "base/blocks/heading_block.html"

第一個子塊,heading_text,使用 CharBlock 來指定標題文本,並且是必需的。第二個子塊,size,使用 ChoiceBlock 來選擇標題大小。它提供 h2、h3 和 h4 的選項。blank=True 和 required=False 使標題文本在你的管理介面中是可選的。

你的 BaseStreamBlock 類繼承自 StreamBlock。StreamBlock 定義了你想要在項目中所有 StreamField 部分中包括的一組子塊類型。這個類為你提供了一組常用塊的基線集合,你可以為你使用 StreamField 的所有不同頁面類型重用和自定義這些塊。例如,你肯定希望編輯者能夠向他們的所有頁面添加圖像和段落文本,但你可能想要創建一個只用於博客頁面的特殊引用塊。

class BaseStreamBlock(StreamBlock):
    heading_block = HeadingBlock()
    paragraph_block = RichTextBlock(icon="pilcrow")
    image_block = ImageBlock()
    embed_block = EmbedBlock(
        help_text="Insert a URL to embed. For example, <https://www.youtube.com/watch?v=SGJFWirQ3ks>",
        icon="media",
    )

你的 BaseStreamBlock 有四個子塊。heading_block 使用之前定義的 HeadingBlock。paragraph_block 使用 RichTextBlock,它提供了一個所見即所得的編輯器來創建格式化文本。image_block 使用之前定義的 ImageBlock 類。embed_block 是用於嵌入外部內容(如視頻)的塊。它使用了 Wagtail 的 EmbedBlock。要了解更多你可以使用的域塊類型,請閱讀有關域塊類型的文檔。

此外,你在 ImageBlock 和 HeadingBlock 塊中定義了 Meta 類。Meta 類提供了塊的元數據,包括在管理介面中視覺上代表它們的圖標。Meta 類還包括用於渲染你的 ImageBlock 和 HeadingBlock 塊的自定義模板。

最後,你必須添加你在 ImageBlock 和 HeadingBlock 塊的 Meta 類中定義的自定義模板。

要添加你的 ImageBlock 的自定義模板,請創建一個 base/templates/base/blocks/image_block.html 文件,並添加以下內容:

.

{% load wagtailimages_tags %}

<figure>
    {% image self.image fill-600x338 loading="lazy" %}
    <figcaption>{{ self.caption }} - {{ self.attribution }}</figcaption>
</figure>

要添加你的 HeadingBlock 塊的自定義模板,請創建一個 base/templates/base/blocks/heading_block.html 文件,並添加以下內容:

{% if self.size == 'h2' %}
    <h2>{{ self.heading_text }}</h2>
{% elif self.size == 'h3' %}
    <h3>{{ self.heading_text }}</h3>
{% elif self.size == 'h4' %}
    <h4>{{ self.heading_text }}</h4>
{% endif %}


使用你在作品集應用程式中創建的區塊
你可以在整個網站中使用你在通用基礎應用程式中創建的可重用自定義區塊。然而,按照慣例,你應該在打算使用它們的應用程式的 blocks.py 檔案中定義你想使用的區塊。然後,你可以從你的應用程式的 blocks.py 檔案導入區塊,在你的 models.py 檔案中使用它們。

現在,創建一個 portfolio/blocks.py 檔案,並按如下方式導入你打算使用的區塊:

from base.blocks import BaseStreamBlock

class PortfolioStreamBlock(BaseStreamBlock):
    pass

上述代碼定義了一個名為 PortfolioStreamBlock 的自定義區塊,它繼承自 BaseStreamBlock。pass 語句表示一個起始點。在本教程的後面部分,你將會向 PortfolioStreamBlock 添加自定義區塊定義和配置。

現在在你的 portfolio/models.py 檔案中添加以下內容:

from wagtail.models import Page
from wagtail.fields import StreamField
from wagtail.admin.panels import FieldPanel

from portfolio.blocks import PortfolioStreamBlock

class PortfolioPage(Page):
    parent_page_types = ["home.HomePage"]

    body = StreamField(
        PortfolioStreamBlock(),
        blank=True,
        use_json_field=True,
        help_text="Use this section to list your projects and skills.",
    )

    content_panels = Page.content_panels + [
        FieldPanel("body"),
    ]

在前面的代碼中,你定義了一個名為 PortfolioPage 的 Wagtail 頁面。parent_page_types = ["home.HomePage"] 指定你的作品集頁面只能是首頁的子頁面。你的 body 字段是一個 StreamField,它使用了從你的 portfolio/blocks.py 文件導入的 PortfolioStreamBlock 自定義區塊。blank=True 表示你可以在管理界面中將此字段留空。help_text 提供了字段的簡短描述,以指導編輯者。

你的下一步是為你的 PortfolioPage 創建一個模板。為此,創建一個 portfolio/templates/portfolio/portfolio_page.html 文件並添加以下內容:

{% extends "base.html" %}

{% load wagtailcore_tags wagtailimages_tags %}

{% block body_class %}template-portfolio{% endblock %}

{% block content %}
    <h1>{{ page.title }}</h1>

    {{ page.body }}
{% endblock %}

加上更多的客制化

要在你的 PortfolioPage 的 body 中添加更多自定義塊,需修改的 portfolio/blocks.py 文件:

# import CharBlock, ListBlock, PageChooserBlock, PageChooserBlock, RichTextBlock, and StructBlock:
from wagtail.blocks import (
    CharBlock,
    ListBlock,
    PageChooserBlock,
    RichTextBlock,
    StructBlock,
)

# import ImageChooserBlock:
from wagtail.images.blocks import ImageChooserBlock

from base.blocks import BaseStreamBlock

# add CardBlock:
class CardBlock(StructBlock):
    heading = CharBlock()
    text = RichTextBlock(features=["bold", "italic", "link"])
    image = ImageChooserBlock(required=False)

    class Meta:
        icon = "form"
        template = "portfolio/blocks/card_block.html"

# add FeaturedPostsBlock:
class FeaturedPostsBlock(StructBlock):
    heading = CharBlock()
    text = RichTextBlock(features=["bold", "italic", "link"], required=False)
    posts = ListBlock(PageChooserBlock(page_type="blog.BlogPage"))

    class Meta:
        icon = "folder-open-inverse"
        template = "portfolio/blocks/featured_posts_block.html"

class PortfolioStreamBlock(BaseStreamBlock):
    # delete the pass statement

    card = CardBlock(group="Sections")
    featured_posts = FeaturedPostsBlock(group="Sections")

在前面的代碼中,CardBlock 有三個子塊:heading、text 和 image。你已經熟悉了這些子頁面所使用的字段塊類型。

然而,在你的 FeaturedPostsBlock 中,其中一個子塊,posts,使用了 ListBlock。ListBlock 是一種結構塊類型,你可以用它來處理多個相同類型的子塊。你將其與 PageChooserBlock 一起使用,只選擇博客頁面類型的頁面。為了更好地理解結構塊類型,請閱讀結構塊類型的文檔。

此外,icon = "form" 和 icon = "folder-open-inverse" 定義了自定義塊圖標,以在管理介面中區分你的塊。關於塊圖標的更多資訊,請閱讀塊圖標的文檔。

你在 card = CardBlock(group="Sections") 和 featured_posts = FeaturedPostsBlock(group="Sections") 中使用了 group="Sections",將你的 card 和 featured_posts 子塊在名為 section 的類別中分類。

你可能知道你的下一步是什麼。你必須為你的 CardBlock 和 FeaturedPostsBlock 創建模板。

要為 CardBlock 創建模板,請創建一個 portfolio/templates/portfolio/blocks/card_block.html 文件,並添加以下內容:

{% load wagtailcore_tags wagtailimages_tags %}
<div class="card">
    <h3>{{ self.heading }}</h3>
    <div>{{ self.text|richtext }}</div>
    {% if self.image %}
        {% image self.image width-480 %}
    {% endif %}
</div>

To create a template for featured_posts_block, create a portfolio/templates/portfolio/blocks/featured_posts_block.html file and add the following to it:

針對 featured_posts_block,要在 portfolio/templates/portfolio/blocks/featured_posts_block.html 加上這段

{% load wagtailcore_tags %}
<div>
    <h2>{{ self.heading }}</h2>
    {% if self.text %}
        <p>{{ self.text|richtext }}</p>
    {% endif %}

    <div class="grid">
        {% for page in self.posts %}
            <div class="card">
                <p><a href="{% pageurl page %}">{{ page.title }}</a></p>
                <p>{{ page.specific.date }}</p>
            </div>
        {% endfor %}
    </div>
</div>

因為動了 models 所以要下

python manage.py makemigrations
python manage.py migrate

添加您的履歷

要將您的履歷添加到您的作品集網站,請按照以下步驟操作:

創建一個作品集頁面作為首頁的子頁面,步驟如下:

a. 重新啟動您的服務器。
b. 轉到您的管理介面。
c. 在側邊欄中點擊 “Pages”。
d. 點擊 “Home”。
e. 點擊結果頁面頂部的 “...” icon。
f. 點擊 “add child page”。
g. 點擊 “Portfolio Page”。

按照以下步驟添加您的履歷數據:
a. 使用“履歷”作為您的頁面標題。
b. 點擊+以展開您的正文部分。
c. 點擊段落塊。
d. 在新的段落塊中複製並粘貼以下文本:

(此處添加您的履歷摘要或描述)

e. 在前一個段落塊下方點擊+,然後點擊段落塊以添加新的段落塊。
f. 在新段落塊的輸入欄中輸入“/”,然後點擊 H2 標題 2。
g. 使用“工作經歷”作為您的標題 2。
h. 在您的標題 2 下方輸入“/”並點擊 H3 標題 3。
i. 使用以下作為您的標題 3:

(此處添加您的工作職稱和公司名稱)

j. 在您的標題 3 之後輸入以下內容:

(此處添加您的工作時間及貢獻)

注意

通過以“-”開始您的句子,您正在將您的工作經歷寫成一個項目符號列表。您也可以通過在段落塊的輸入欄中輸入“/”,然後點擊項目符號列表來達到相同的效果。

k. 在您的工作經驗下方點擊+。
l. 點擊段落塊以添加另一個段落塊。
m. 在新段落塊的輸入欄中輸入“/”,然後點擊 H2 標題 2。
n. 使用“技能”作為新段落塊的標題 2。
o. 在您的標題 2 之後複製並粘貼以下內容:

(此處添加您的技能列表)

發布您的作品集頁面。

恭喜!🎉 您現在了解如何使用 Wagtail StreamField 創建複雜的靈活佈局。下一部分,您將學習如何為您的網站添加搜索功能。


上一篇
D15 - 創造一個可填寫的表單 - 以聯絡用表單為例
下一篇
D17 - 在網站加上 Search - 搜索 的功能
系列文
使用 Django 框架和 Wagtail,快速打造一個 CMS 網站30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言