時間:2023-07-11 04:54:02 | 來源:網(wǎng)站運(yùn)營
時間:2023-07-11 04:54:02 來源:網(wǎng)站運(yùn)營
Wagtail建站入門指南:venv
,它與 Python 3 一起打包。$ python3 -m venv mysiteenv$ mysite/env/Scripts/activate.bat
在 GNU/Linux 或 MacOS (bash) 上:$ python3 -m venv mysite/env$ source mysite/env/bin/activate
**對于其他 shell,**請參閱ref="https://docs.python.org/3/library/venv.html">venv文檔。
mysite
將是您項目的目錄。env
它里面的目錄應(yīng)該從任何版本控制中排除。start
類似于. 在您的項目中運(yùn)行將生成一個新文件夾,其中包含一些特定于 Wagtail 的附加功能,包括所需的項目設(shè)置、一個帶有空白模型和基本模板的“home”應(yīng)用程序,以及一個示例“搜索”應(yīng)用程序。django-admin startproject``wagtail start mysite``mysite``HomePage
mysite
已由 創(chuàng)建venv
,請使用附加參數(shù)運(yùn)行以指定目標(biāo)目錄:wagtail start
INSTALLED_APPS
在settings
文件部分注冊。查看此文件以了解start
命令如何在其中列出它們。HomePage
模型models.py
,以及創(chuàng)建主頁并配置 Wagtail 以使用它的遷移。home/models.py
如下,向body
模型添加一個字段:from django.db import modelsfrom wagtail.core.models import Pagefrom wagtail.core.fields import RichTextFieldfrom wagtail.admin.edit_handlers import FieldPanelclass HomePage(Page): body = RichTextField(blank=True) content_panels = Page.content_panels + [ FieldPanel('body', classname="full"), ]
body
被定義為RichTextField
,一個特殊的 Wagtail 字段。當(dāng) 時blank=True
,表示該字段不是必需的,可以為空。您可以使用任何Django 核心字段。content_panels
定義編輯界面的功能和布局。向 中添加字段時content_panels
,可以在 Wagtail 界面上對其進(jìn)行編輯。有關(guān)創(chuàng)建頁面模型的更多信息。python manage.py makemigrations``python manage.py migrate
home/home_page.html
)。這個模板文件可以存在于Django 模板規(guī)則識別的任何位置 ;通常它被放置在templates
應(yīng)用程序內(nèi)的文件夾下。home/templates/home/home_page.html
以包含以下內(nèi)容:{% extends "base.html" %}{% load wagtailcore_tags %}{% block body_class %}template-homepage{% endblock %}{% block content %} {{ page.body|richtext }}{% endblock %}
base.html
引用父模板并且必須始終是模板中使用的第一個模板標(biāo)記。從此模板擴(kuò)展可以避免重寫代碼,并允許應(yīng)用程序中的頁面共享相似的框架(通過在子模板中使用塊標(biāo)記,您可以覆蓋父模板中的特定內(nèi)容)。wagtailcore_tags
還必須在模板頂部加載,并為 Django 提供的標(biāo)簽提供額外的標(biāo)簽。python manage.py startapp blog
blog
的應(yīng)用程序,以INSTALLED_APPS
在mysite/settings/base.py
。blog/models.py
:from wagtail.core.models import Pagefrom wagtail.core.fields import RichTextFieldfrom wagtail.admin.edit_handlers import FieldPanelclass BlogIndexPage(Page): intro = RichTextField(blank=True) content_panels = Page.content_panels + [ FieldPanel('intro', classname="full") ]
運(yùn)行和。python manage.py makemigrations``python manage.py migrate
BlogIndexPage
,默認(rèn)模板名稱(除非我們覆蓋它)將是blog/templates/blog/blog_index_page.html
. 使用以下內(nèi)容創(chuàng)建此文件:{% extends "base.html" %}{% load wagtailcore_tags %}{% block body_class %}template-blogindexpage{% endblock %}{% block content %} <h1>{{ page.title }}</h1> <div class="intro">{{ page.intro|richtext }}</div> {% for post in page.get_children %} <h2><a href="{% pageurl post %}">{{ post.title }}</a></h2> {{ post.specific.intro }} {{ post.specific.body|richtext }} {% endfor %}{% endblock %}
大部分內(nèi)容應(yīng)該很熟悉,但我們稍后會解釋get_children
。請注意pageurl
標(biāo)簽,它類似于 Django 的url
標(biāo)簽,但采用 Wagtail Page 對象作為參數(shù)。BlogIndexPage
作為主頁的子項,確保它在“推廣”選項卡上有“博客”,然后發(fā)布它。您現(xiàn)在應(yīng)該能夠訪問/blog
您網(wǎng)站上的 url (注意“提升”選項卡中的 slug 如何定義頁面 URL)。blog/models.py
:from django.db import modelsfrom wagtail.core.models import Pagefrom wagtail.core.fields import RichTextFieldfrom wagtail.admin.edit_handlers import FieldPanelfrom wagtail.search import index# Keep the definition of BlogIndexPage, and add:class BlogPage(Page): date = models.DateField("Post date") intro = models.CharField(max_length=250) body = RichTextField(blank=True) search_fields = Page.search_fields + [ index.SearchField('intro'), index.SearchField('body'), ] content_panels = Page.content_panels + [ FieldPanel('date'), FieldPanel('intro'), FieldPanel('body', classname="full"), ]
在上面的模型中,我們導(dǎo)入,index
因為這使模型可搜索。然后,您可以列出您希望可供用戶搜索的字段。python manage.py makemigrations``python manage.py migrate
blog/templates/blog/blog_page.html
以下位置創(chuàng)建模板:{% extends "base.html" %}{% load wagtailcore_tags %}{% block body_class %}template-blogpage{% endblock %}{% block content %} <h1>{{ page.title }}</h1> <p class="meta">{{ page.date }}</p> <div class="intro">{{ page.intro }}</div> {{ page.body|richtext }} <p><a href="{{ page.get_parent.url }}">Return to blog</a></p>{% endblock %}
請注意使用 Wagtail 的內(nèi)置get_parent()
方法來獲取此帖子所屬博客的 URL。BlogIndexPage
. 創(chuàng)建帖子時,請務(wù)必選擇“博客頁面”類型。/blog
URL,您應(yīng)該會看到如下內(nèi)容:BlogIndexPage
是一個“節(jié)點”,單個BlogPage
實例是“葉子”。blog_index_page.html
:{% for post in page.get_children %} <h2><a href="{% pageurl post %}">{{ post.title }}</a></h2> {{ post.specific.intro }} {{ post.specific.body|richtext }}{% endfor %}
Wagtail 中的每個“頁面”都可以從其在層次結(jié)構(gòu)中的位置調(diào)用其父級或子級。但是為什么我們必須指定post.specific.intro
而不是post.intro
?這與我們定義模型的方式有關(guān):class BlogPage(Page):
get_children()
方法為我們獲取Page
基類的實例列表。當(dāng)我們想要引用從基類繼承的實例的屬性時,Wagtail 提供了specific
檢索實際BlogPage
記錄的方法。雖然“title”字段存在于基本Page
模型中,但“intro”只存在于BlogPage
模型中,因此我們需要.specific
訪問它。with
標(biāo)簽:{% for post in page.get_children %} {% with post=post.specific %} <h2><a href="{% pageurl post %}">{{ post.title }}</a></h2> <p>{{ post.intro }}</p> {{ post.body|richtext }} {% endwith %}{% endfor %}
當(dāng)您開始編寫更多定制的 Wagtail 代碼時,您會發(fā)現(xiàn)一整套 QuerySet 修飾符來幫助您導(dǎo)航層次結(jié)構(gòu)。# Given a page object 'somepage':MyModel.objects.descendant_of(somepage)child_of(page) / not_child_of(somepage)ancestor_of(somepage) / not_ancestor_of(somepage)parent_of(somepage) / not_parent_of(somepage)sibling_of(somepage) / not_sibling_of(somepage)# ... and ...somepage.get_children()somepage.get_ancestors()somepage.get_descendants()somepage.get_siblings()
更多信息請參見:頁面查詢集參考get_context()
方法使這成為可能。BlogIndexPage
像這樣修改你的模型:class BlogIndexPage(Page): intro = RichTextField(blank=True) def get_context(self, request): # Update context to include only published posts, ordered by reverse-chron context = super().get_context(request) blogpages = self.get_children().live().order_by('-first_published_at') context['blogpages'] = blogpages return context
我們在這里所做的只是檢索原始上下文,創(chuàng)建自定義 QuerySet,將其添加到檢索到的上下文中,并將修改后的上下文返回給視圖。您還需要blog_index_page.html
稍微修改模板。改變:{% for post in page.get_children %}
到 {% for post in blogpages %}
body
富文本字段,但將我們的畫廊圖像設(shè)置為數(shù)據(jù)庫中新的專用對象類型有幾個優(yōu)點 - 這樣,您可以完全控制圖像上的布局和樣式模板,而不必在富文本字段中以特定方式布置它們。它還使圖像可以在別處使用,獨立于博客文本 - 例如,在博客索引頁面上顯示縮略圖。BlogPageGalleryImage
模型到models.py
:from django.db import models# New imports added for ParentalKey, Orderable, InlinePanel, ImageChooserPanelfrom modelcluster.fields import ParentalKeyfrom wagtail.core.models import Page, Orderablefrom wagtail.core.fields import RichTextFieldfrom wagtail.admin.edit_handlers import FieldPanel, InlinePanelfrom wagtail.images.edit_handlers import ImageChooserPanelfrom wagtail.search import index# ... (Keep the definition of BlogIndexPage, and update BlogPage:)class BlogPage(Page): date = models.DateField("Post date") intro = models.CharField(max_length=250) body = RichTextField(blank=True) search_fields = Page.search_fields + [ index.SearchField('intro'), index.SearchField('body'), ] content_panels = Page.content_panels + [ FieldPanel('date'), FieldPanel('intro'), FieldPanel('body', classname="full"), InlinePanel('gallery_images', label="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) panels = [ ImageChooserPanel('image'), FieldPanel('caption'), ]
運(yùn)行和。python manage.py makemigrations``python manage.py migrate
Orderable
添加一個sort_order
字段,以跟蹤圖庫中圖像的順序。ParentalKey
到BlogPage
什么高度圖庫圖片到指定的頁面。A 的ParentalKey
工作方式與 a 類似ForeignKey
,但也定義BlogPageGalleryImage
為BlogPage
模型的“子項” ,因此在提交審核和跟蹤修訂歷史等操作中,它被視為頁面的基本部分。image
是ForeignKey
Wagtail 的內(nèi)置Image
模型,其中存儲了圖像本身。它帶有專用面板類型 ,ImageChooserPanel
它提供了一個用于選擇現(xiàn)有圖像或上傳新圖像的彈出界面。這樣,我們允許一個圖像存在于多個畫廊中——實際上,我們在頁面和圖像之間創(chuàng)建了多對多關(guān)系。on_delete=models.CASCADE
在外鍵上指定意味著如果圖像從系統(tǒng)中刪除,圖庫條目也將被刪除。(在其他情況下,將條目留在原處可能是合適的 - 例如,如果“我們的員工”頁面包含有頭像的人的列表,并且其中一張照片被刪除,我們寧愿將該人留在放置在沒有照片的頁面上。在這種情況下,我們將外鍵設(shè)置為。)blank=True, null=True, on_delete=models.SET_NULL
InlinePanel
到BlogPage.content_panels
品牌的編輯界面上可用的畫廊圖像BlogPage
。{% extends "base.html" %}{% load wagtailcore_tags wagtailimages_tags %}{% block body_class %}template-blogpage{% endblock %}{% block content %} <h1>{{ page.title }}</h1> <p class="meta">{{ page.date }}</p> <div class="intro">{{ page.intro }}</div> {{ page.body|richtext }} {% for item in page.gallery_images.all %} <div style="float: left; margin: 10px"> {% image item.image fill-320x240 %} <p>{{ item.caption }}</p> </div> {% endfor %} <p><a href="{{ page.get_parent.url }}">Return to blog</a></p>{% endblock %}
這里我們使用標(biāo)簽(存在于庫中,在模板頂部導(dǎo)入)插入一個元素,帶有一個參數(shù)來指示應(yīng)該調(diào)整圖像大小和裁剪以填充 320x240 矩形。您可以在docs 中閱讀有關(guān)在模板中使用圖像的更多信息。{% image %}``wagtailimages_tags``<img>``fill-320x240
main_image
方法,它從第一個畫廊項目(或者None
如果不存在畫廊項目)返回圖像:class BlogPage(Page): date = models.DateField("Post date") intro = models.CharField(max_length=250) body = RichTextField(blank=True) def main_image(self): gallery_item = self.gallery_images.first() if gallery_item: return gallery_item.image else: return None search_fields = Page.search_fields + [ index.SearchField('intro'), index.SearchField('body'), ] content_panels = Page.content_panels + [ FieldPanel('date'), FieldPanel('intro'), FieldPanel('body', classname="full"), InlinePanel('gallery_images', label="Gallery images"), ]
現(xiàn)在可以從我們的模板中使用此方法。更新blog_index_page.html
以將主圖像作為縮略圖包含在每個帖子旁邊:{% load wagtailcore_tags wagtailimages_tags %}{% for post in blogpages %} {% with post=post.specific %} <h2><a href="{% pageurl post %}">{{ post.title }}</a></h2> {% with post.main_image as main_image %} {% if main_image %}{% image main_image fill-160x100 %}{% endif %} {% endwith %} <p>{{ post.intro }}</p> {{ post.body|richtext }} {% endwith %}{% endfor %}
BlogPage
模型和內(nèi)容面板,并在博客帖子模板上呈現(xiàn)鏈接標(biāo)簽。當(dāng)然,我們還需要一個工作標(biāo)簽特定的 URL 視圖。models.py
再次修改:from django.db import models# New imports added for ClusterTaggableManager, TaggedItemBase, MultiFieldPanelfrom modelcluster.fields import ParentalKeyfrom modelcluster.contrib.taggit import ClusterTaggableManagerfrom taggit.models import TaggedItemBasefrom wagtail.core.models import Page, Orderablefrom wagtail.core.fields import RichTextFieldfrom wagtail.admin.edit_handlers import FieldPanel, InlinePanel, MultiFieldPanelfrom wagtail.images.edit_handlers import ImageChooserPanelfrom wagtail.search import index# ... (Keep the definition of BlogIndexPage)class BlogPageTag(TaggedItemBase): content_object = ParentalKey( 'BlogPage', related_name='tagged_items', on_delete=models.CASCADE )class BlogPage(Page): date = models.DateField("Post date") intro = models.CharField(max_length=250) body = RichTextField(blank=True) tags = ClusterTaggableManager(through=BlogPageTag, blank=True) # ... (Keep the main_image method and search_fields definition) content_panels = Page.content_panels + [ MultiFieldPanel([ FieldPanel('date'), FieldPanel('tags'), ], heading="Blog information"), FieldPanel('intro'), FieldPanel('body'), InlinePanel('gallery_images', label="Gallery images"), ]
運(yùn)行和。python manage.py makemigrations``python manage.py migrate
modelcluster
和taggit
進(jìn)口的、新 BlogPageTag
模型的添加以及 上的tags
字段的添加BlogPage
。我們還借此機(jī)會使用MultiFieldPanel
incontent_panels
將日期和標(biāo)簽字段組合在一起以提高可讀性。BlogPage
實例之一,您現(xiàn)在應(yīng)該能夠標(biāo)記帖子:BlogPage
,請將其添加到blog_page.html
:{% if page.tags.all.count %} <div class="tags"> <h3>Tags</h3> {% for tag in page.tags.all %} <a href="{% slugurl 'tags' %}?tag={{ tag }}"><button type="button">{{ tag }}</button></a> {% endfor %} </div>{% endif %}
請注意,我們使用內(nèi)置slugurl
標(biāo)記而不是pageurl
我們之前使用的鏈接到此處的頁面。不同之處在于slugurl
它以 Page slug(來自“提升”選項卡)作為參數(shù)。pageurl
更常用,因為它是明確的并且避免了額外的數(shù)據(jù)庫查找。但是在這個循環(huán)的情況下,Page 對象不是隨時可用的,所以我們回到不太喜歡的slugurl
標(biāo)簽。models.py
:class BlogTagIndexPage(Page): def get_context(self, request): # Filter by tag tag = request.GET.get('tag') blogpages = BlogPage.objects.filter(tags__name=tag) # Update template context context = super().get_context(request) context['blogpages'] = blogpages return context
請注意,這個基于頁面的模型沒有定義自己的字段。即使沒有字段,子類化Page
也使它成為 Wagtail 生態(tài)系統(tǒng)的一部分,這樣你就可以在管理中給它一個標(biāo)題和 URL,這樣你就可以通過從它的get_context()
方法返回一個 QuerySet 來操縱它的內(nèi)容。BlogTagIndexPage
在管理員中創(chuàng)建一個新的。您可能希望將新頁面/視圖創(chuàng)建為 Homepage 的子項,與您的博客索引平行。在“提升”選項卡上為其添加 slug“標(biāo)簽”。/tags
和 Django 會告訴你你可能已經(jīng)知道的事情:你需要創(chuàng)建一個模板blog/blog_tag_index_page.html
:{% extends "base.html" %}{% load wagtailcore_tags %}{% block content %} {% if request.GET.tag %} <h4>Showing pages tagged "{{ request.GET.tag }}"</h4> {% endif %} {% for blogpage in blogpages %} <p> <strong><a href="{% pageurl blogpage %}">{{ blogpage.title }}</a></strong><br /> <small>Revised: {{ blogpage.latest_revision_created_at }}</small><br /> {% if blogpage.author %} <p>By {{ blogpage.author.profile }}</p> {% endif %} </p> {% empty %} No pages found with that tag. {% endfor %}{% endblock %}
我們正在調(diào)用 模型latest_revision_created_at
上的內(nèi)置字段Page
- 知道這總是可用的很方便。BlogPage
模型中添加一個“作者”字段,我們也沒有作者的 Profile 模型——我們將這些留給讀者作為練習(xí)。BlogCategory
模型。類別本身并不是一個頁面,因此我們將其定義為標(biāo)準(zhǔn)的 Django,models.Model
而不是從Page
. Wagtail 為需要通過管理界面管理但不作為頁面樹本身的一部分存在的可重用內(nèi)容片段引入了“片段”的概念;可以通過添加@register_snippet
裝飾器將模型注冊為片段。到目前為止,我們在頁面上使用的所有字段類型也可以用于片段 - 在這里,我們將為每個類別提供一個圖標(biāo)圖像和一個名稱。添加到blog/models.py
:from wagtail.snippets.models import register_snippet@register_snippetclass BlogCategory(models.Model): name = models.CharField(max_length=255) icon = models.ForeignKey( 'wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+' ) panels = [ FieldPanel('name'), ImageChooserPanel('icon'), ] def __str__(self): return self.name class Meta: verbose_name_plural = 'blog categories'
請注意,我們正在使用panels
而不是content_panels
在這里 - 由于片段通常不需要諸如 slug 或發(fā)布日期之類的字段,因此它們的編輯界面不會作為標(biāo)準(zhǔn)拆分為單獨的“內(nèi)容”/“推廣”/“設(shè)置”選項卡,并且因此無需區(qū)分“內(nèi)容面板”和“推廣面板”。BlogPage
模型添加類別,作為多對多字段。我們?yōu)榇耸褂玫淖侄晤愋褪?code>ParentalManyToManyField- 這是標(biāo)準(zhǔn) Django 的變體,ManyToManyField
它確保所選對象正確存儲在修訂歷史記錄中的頁面記錄中,與ParentalKey
替換ForeignKey
一對多關(guān)系的方式大致相同。# New imports added for forms and ParentalManyToManyFieldfrom django import formsfrom django.db import modelsfrom modelcluster.fields import ParentalKey, ParentalManyToManyFieldfrom modelcluster.contrib.taggit import ClusterTaggableManagerfrom taggit.models import TaggedItemBase# ...class BlogPage(Page): date = models.DateField("Post date") intro = models.CharField(max_length=250) body = RichTextField(blank=True) tags = ClusterTaggableManager(through=BlogPageTag, blank=True) categories = ParentalManyToManyField('blog.BlogCategory', blank=True) # ... (Keep the main_image method and search_fields definition) content_panels = Page.content_panels + [ MultiFieldPanel([ FieldPanel('date'), FieldPanel('tags'), FieldPanel('categories', widget=forms.CheckboxSelectMultiple), ], heading="Blog information"), FieldPanel('intro'), FieldPanel('body'), InlinePanel('gallery_images', label="Gallery images"), ]
在這里,我們使用定義中的widget
關(guān)鍵字參數(shù)FieldPanel
來指定基于復(fù)選框的小部件而不是默認(rèn)的多選框,因為這通常被認(rèn)為對用戶更友好。blog_page.html
模板以顯示類別:<h1>{{ page.title }}</h1><p class="meta">{{ page.date }}</p>{% with categories=page.categories.all %} {% if categories %} <h3>Posted in:</h3> <ul> {% for category in categories %} <li style="display: inline"> {% image category.icon fill-32x32 style="vertical-align: middle" %} {{ category.name }} </li> {% endfor %} </ul> {% endif %}{% endwith %}
關(guān)鍵詞:指南,入門
客戶&案例
微信公眾號
版權(quán)所有? 億企邦 1997-2025 保留一切法律許可權(quán)利。