15158846557 在线咨询 在线咨询
15158846557 在线咨询
所在位置: 首页 > 营销资讯 > 网站运营 > Wagtail建站入门指南

Wagtail建站入门指南

时间:2023-07-11 04:54:02 | 来源:网站运营

时间:2023-07-11 04:54:02 来源:网站运营

Wagtail建站入门指南:

Wagtail建站入门指南

安装并运行 Wagtail ¶[1]

安装依赖项¶[2]

Wagtail 支持 Python 3.6、3.7、3.8、3.9 和 3.10。

要检查您是否有合适的 Python 3 版本:

如果这不返回版本号或返回低于 3.6 的版本,则需要安装 Python 3。

重要的

在安装 Wagtail 之前,需要安装libjpegzlib库,它们支持处理 JPEG、PNG 和 GIF 图像(通过 Python Pillow库)。执行此操作的方法因平台而异 - 请参阅 Pillow 特定于平台的安装说明。

创建并激活虚拟环境¶[3]

我们建议使用虚拟环境,它将已安装的依赖项与其他项目隔离开来。本教程使用venv,它与 Python 3 一起打包。

在 Windows (cmd.exe) 上:

$ 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文档。

笔记

如果您使用版本控制(例如 git),mysite将是您项目的目录。env它里面的目录应该从任何版本控制中排除。

安装 Wagtail ¶[4]

使用Python自带的pip安装Wagtail及其依赖:

生成您的站点¶[5]

Wagtail 提供了一个start类似于. 在您的项目中运行将生成一个新文件夹,其中包含一些特定于 Wagtail 的附加功能,包括所需的项目设置、一个带有空白模型和基本模板的“home”应用程序,以及一个示例“搜索”应用程序。django-admin startproject``wagtail start mysite``mysite``HomePage

由于该文件夹mysite已由 创建venv,请使用附加参数运行以指定目标目录:wagtail start

$ wagtail start mysite mysite

笔记

通常,在 Wagtail 中,每个页面类型或内容类型由单个应用程序表示。但是,不同的应用程序可以相互了解并访问彼此的数据。所有应用程序都需要INSTALLED_APPSsettings文件部分注册。查看此文件以了解start命令如何在其中列出它们。

安装项目依赖项¶[6]

cd mysite pip install -r requirements.txt

这确保您拥有相关版本的 Wagtail、Django 以及您刚刚创建的项目的任何其他依赖项。

创建数据库¶[7]

如果您尚未更新项目设置,这将是项目目录中的 SQLite 数据库文件。

$ python manage.py migrate

此命令可确保数据库中的表与项目中的模型匹配。每次更改模型时(例如,您可以向模型添加字段),您都需要运行此命令以更新数据库。

创建管理员用户¶[8]

$ python manage.py createsuperuser

当登录到管理站点时,超级用户具有完全权限并且能够查看/创建/管理数据库。

扩展主页模型¶[9]

开箱即用,“home”应用程序在 中定义了一个空白HomePage模型models.py,以及创建主页并配置 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 字段。当 时blank=True,表示该字段不是必需的,可以为空。您可以使用任何Django 核心字段。content_panels定义编辑界面的功能和布局。向 中添加字段时content_panels,可以在 Wagtail 界面上对其进行编辑。有关创建页面模型的更多信息。

运行(这将创建迁移文件),然后 (这将执行迁移并使用您的模型更改更新数据库)。每次更改模型定义时都必须运行上述命令。python manage.py makemigrations``python manage.py migrate

您现在可以在 Wagtail 管理区域内编辑主页(转到页面、主页,然后编辑)以查看新的正文字段。在正文字段中输入一些文本,然后通过选择页面编辑器底部的_Publish_而不是_Save Draft_来_发布_页面。

现在需要更新页面模板以反映对模型所做的更改。Wagtail 使用普通的 Django 模板来呈现每种页面类型。默认情况下,它将查找由应用程序和模型名称组成的模板文件名,用下划线分隔大写字母(例如,“home”应用程序中的 HomePage 变为 home/home_page.html)。这个模板文件可以存在于Django 模板规则识别的任何位置 ;通常它被放置在templates应用程序内的文件夹下。

编辑home/templates/home/home_page.html以包含以下内容:

{% extends "base.html" %}{% load wagtailcore_tags %}{% block body_class %}template-homepage{% endblock %}{% block content %} {{ page.body|richtext }}{% endblock %}base.html引用父模板并且必须始终是模板中使用的第一个模板标记。从此模板扩展可以避免重写代码,并允许应用程序中的页面共享相似的框架(通过在子模板中使用块标记,您可以覆盖父模板中的特定内容)。

wagtailcore_tags 还必须在模板顶部加载,并为 Django 提供的标签提供额外的标签。

一个基本的博客¶[10]

我们现在准备创建一个博客。为此,请运行 以在您的 Wagtail 站点中创建一个新应用程序。python manage.py startapp blog

新添加blog的应用程序,以INSTALLED_APPSmysite/settings/base.py

博客索引和帖子¶[11]

让我们从一个简单的博客索引页开始。在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") ]运行和。python manage.py makemigrations``python manage.py migrate

由于模型被调用BlogIndexPage,默认模板名称(除非我们覆盖它)将是blog/templates/blog/blog_index_page.html. 使用以下内容创建此文件:

{% 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 %}大部分内容应该很熟悉,但我们稍后会解释get_children。请注意pageurl标签,它类似于 Django 的url标签,但采用 Wagtail Page 对象作为参数。

在 Wagtail 管理员中,创建一个BlogIndexPage作为主页的子项,确保它在“推广”选项卡上有“博客”,然后发布它。您现在应该能够访问/blog您网站上的 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"), ]在上面的模型中,我们导入,index因为这使模型可搜索。然后,您可以列出您希望可供用户搜索的字段。

运行和。python manage.py makemigrations``python manage.py migrate

blog/templates/blog/blog_page.html以下位置创建模板:

{% 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 的内置get_parent()方法来获取此帖子所属博客的 URL。

现在创建一些博客文章作为BlogIndexPage. 创建帖子时,请务必选择“博客页面”类型。

Wagtail 使您可以完全控制在各种父内容类型下可以创建哪些类型的内容。默认情况下,任何页面类型都可以是任何其他页面类型的子页面。

完成编辑后发布每篇博文。

你现在应该有一个工作博客的开始。访问/blogURL,您应该会看到如下内容:

标题应该链接到帖子页面,返回博客主页的链接应该出现在每个帖子页面的页脚中。

父母和孩子¶[12]

您将在 Wagtail 中进行的大部分工作都围绕由节点和叶子组成的分层“树”结构的概念(请参阅理论)。在这种情况下,BlogIndexPage是一个“节点”,单个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 中的每个“页面”都可以从其在层次结构中的位置调用其父级或子级。但是为什么我们必须指定post.specific.intro而不是post.intro?这与我们定义模型的方式有关:

class BlogPage(Page):

get_children()方法为我们获取Page基类的实例列表。当我们想要引用从基类继承的实例的属性时,Wagtail 提供了specific检索实际BlogPage记录的方法。虽然“title”字段存在于基本Page模型中,但“intro”只存在于BlogPage模型中,因此我们需要.specific访问它。

为了收紧这样的模板代码,我们可以使用 Django 的with标签:

{% 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 %}当您开始编写更多定制的 Wagtail 代码时,您会发现一整套 QuerySet 修饰符来帮助您导航层次结构。

# 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()更多信息请参见:页面查询集参考

覆盖上下文¶[13]

我们的博客索引视图有几个问题:

  1. 博客一般按时间_倒序_显示内容
  2. 我们要确保我们只显示_已发布的_内容。
为了完成这些事情,我们需要做的不仅仅是在模板中获取索引页面的子页面。相反,我们希望修改模型定义中的 QuerySet。Wagtail 通过 overridableget_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我们在这里所做的只是检索原始上下文,创建自定义 QuerySet,将其添加到检索到的上下文中,并将修改后的上下文返回给视图。您还需要blog_index_page.html稍微修改模板。改变:

{% for post in page.get_children %}{% for post in blogpages %}

现在尝试取消发布您的一篇文章 - 它应该从博客索引页面中消失。剩下的帖子现在应该首先按照最近发布的帖子排序。

图像¶[14]

让我们添加将图片库附加到我们的博客文章的功能。虽然可以简单地将图像插入body富文本字段,但将我们的画廊图像设置为数据库中新的专用对象类型有几个优点 - 这样,您可以完全控制图像上的布局和样式模板,而不必在富文本字段中以特定方式布置它们。它还使图像可以在别处使用,独立于博客文本 - 例如,在博客索引页面上显示缩略图。

添加一个新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'), ]运行和。python manage.py makemigrations``python manage.py migrate

这里有一些新概念,所以让我们一次一个:

继承自向模型Orderable添加一个sort_order字段,以跟踪图库中图像的顺序。

ParentalKeyBlogPage什么高度图库图片到指定的页面。A 的ParentalKey工作方式与 a 类似ForeignKey,但也定义BlogPageGalleryImageBlogPage模型的“子项” ,因此在提交审核和跟踪修订历史等操作中,它被视为页面的基本部分。

imageForeignKeyWagtail 的内置Image模型,其中存储了图像本身。它带有专用面板类型 ,ImageChooserPanel它提供了一个用于选择现有图像或上传新图像的弹出界面。这样,我们允许一个图像存在于多个画廊中——实际上,我们在页面和图像之间创建了多对多关系。

on_delete=models.CASCADE在外键上指定意味着如果图像从系统中删除,图库条目也将被删除。(在其他情况下,将条目留在原处可能是合适的 - 例如,如果“我们的员工”页面包含有头像的人的列表,并且其中一张照片被删除,我们宁愿将该人留在放置在没有照片的页面上。在这种情况下,我们将外键设置为。)blank=True, null=True, on_delete=models.SET_NULL

最后,加入InlinePanelBlogPage.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 %}这里我们使用标签(存在于库中,在模板顶部导入)插入一个元素,带有一个参数来指示应该调整图像大小和裁剪以填充 320x240 矩形。您可以在docs 中阅读有关在模板中使用图像的更多信息。{% 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"), ]现在可以从我们的模板中使用此方法。更新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 %}

标记帖子¶[15]

假设我们想让编辑“标记”他们的帖子,这样读者就可以,例如,一起查看所有与自行车相关的内容。为此,我们需要调用与 Wagtail 捆绑在一起的标记系统,将其附加到BlogPage 模型和内容面板,并在博客帖子模板上呈现链接标签。当然,我们还需要一个工作标签特定的 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"), ]运行和。python manage.py makemigrations``python manage.py migrate

请注意新的modelclustertaggit进口的、新 BlogPageTag模型的添加以及 上的tags字段的添加BlogPage。我们还借此机会使用MultiFieldPanelincontent_panels 将日期和标签字段组合在一起以提高可读性。

编辑您的BlogPage实例之一,您现在应该能够标记帖子:

要在 上呈现标签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 %}请注意,我们使用内置slugurl 标记而不是pageurl我们之前使用的链接到此处的页面。不同之处在于slugurl它以 Page slug(来自“提升”选项卡)作为参数。pageurl更常用,因为它是明确的并且避免了额外的数据库查找。但是在这个循环的情况下,Page 对象不是随时可用的,所以我们回到不太喜欢的slugurl标签。

访问带有标签的博客文章现在应该在底部显示一组链接按钮 - 每个标签一个。但是,单击按钮会得到 404,因为我们还没有定义“标签”视图。添加到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 生态系统的一部分,这样你就可以在管理中给它一个标题和 URL,这样你就可以通过从它的get_context()方法返回一个 QuerySet 来操纵它的内容。

将其迁移进来,然后BlogTagIndexPage在管理员中创建一个新的。您可能希望将新页面/视图创建为 Homepage 的子项,与您的博客索引平行。在“提升”选项卡上为其添加 slug“标签”。

Access/tags和 Django 会告诉你你可能已经知道的事情:你需要创建一个模板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 %}我们正在调用 模型latest_revision_created_at上的内置字段Page- 知道这总是可用的很方便。

我们还没有在我们的BlogPage模型中添加一个“作者”字段,我们也没有作者的 Profile 模型——我们将这些留给读者作为练习。

单击博客帖子底部的标签按钮现在应该呈现如下页面:

类别¶[16]

让我们为我们的博客添加一个类别系统。与标签不同,页面作者只需在页面上使用标签即可将标签引入,我们的类别将是一个固定列表,由站点所有者通过管理界面的单独区域进行管理。

首先,我们定义一个BlogCategory模型。类别本身并不是一个页面,因此我们将其定义为标准的 Django,models.Model而不是从Page. Wagtail 为需要通过管理界面管理但不作为页面树本身的一部分存在的可重用内容片段引入了“片段”的概念;可以通过添加@register_snippet装饰器将模型注册为片段。到目前为止,我们在页面上使用的所有字段类型也可以用于片段 - 在这里,我们将为每个类别提供一个图标图像和一个名称。添加到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 或发布日期之类的字段,因此它们的编辑界面不会作为标准拆分为单独的“内容”/“推广”/“设置”选项卡,并且因此无需区分“内容面板”和“推广面板”。

迁移此更改,并通过现在显示在管理菜单中的代码段区域创建一些类别。

我们现在可以向BlogPage模型添加类别,作为多对多字段。我们为此使用的字段类型是ParentalManyToManyField- 这是标准 Django 的变体,ManyToManyField它确保所选对象正确存储在修订历史记录中的页面记录中,与ParentalKey替换ForeignKey一对多关系的方式大致相同。

# 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关键字参数FieldPanel来指定基于复选框的小部件而不是默认的多选框,因为这通常被认为对用户更友好。

最后,我们可以更新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 %}

参考资料

[1]

固定链接到这个标题: #install-and-run-wagtail

[2]

固定链接到这个标题: #install-dependencies

[3]

固定链接到这个标题: #create-and-activate-a-virtual-environment

[4]

固定链接到这个标题: #install-wagtail

[5]

固定链接到这个标题: #generate-your-site

[6]

固定链接到这个标题: #install-project-dependencies

[7]

固定链接到这个标题: #create-the-database

[8]

固定链接到这个标题: #create-an-admin-user

[9]

固定链接到这个标题: #extend-the-homepage-model

[10]

固定链接到这个标题: #a-basic-blog

[11]

固定链接到这个标题: #blog-index-and-posts

[12]

固定链接到这个标题: #parents-and-children

[13]

固定链接到这个标题: #overriding-context

[14]

固定链接到这个标题: #images

[15]

固定链接到这个标题: #tagging-posts

[16]

固定链接到这个标题: #categories

关键词:指南,入门

74
73
25
news

版权所有© 亿企邦 1997-2025 保留一切法律许可权利。

为了最佳展示效果,本站不支持IE9及以下版本的浏览器,建议您使用谷歌Chrome浏览器。 点击下载Chrome浏览器
关闭