当前位置:首页 > 技术分析 > 正文内容

Wagtail建站入门(二)

ruisui882个月前 (03-16)技术分析14

Wagtail是一款基于Django的CMS开源框架,集成的功能非常多,很适合做定制站点开发。本文是从Wagtail官网翻译的一篇教程(官网教程:Your first Wagtail site),由于原文比较长,我把它分成了三个部分,今天这篇文章是第二部分,主要内容是搭建能够显示博客列表和博客文章的一个简单博客。

如果您还没有看过前面的教程,可以参考:

Wagtail建站入门(一)

一个简单的博客应用

现在我们准备创建一个简单的博客应用,首先,运行下面的命令,在我们的项目中创建一个blog应用。

python manage.py startapp blog

在mysite/settings/base.py 的INSTALLED_APPS中添加blog。

博客列表和博客文章(post)

让我们从创建博客列表的页面开始,在blog/models.py中,编辑代码如下:

from wagtail.models import Page
from wagtail.fields import RichTextField
from wagtail.admin.panels import FieldPanel
 
class BlogIndexPage(Page):
    intro = RichTextField(blank=True)
 
    content_panels = Page.content_panels + [
        FieldPanel('intro', classname="full")
    ]

运行

python manage.py makemigrations
python manage.py migrate

因为Model的名称叫BlogIndexPage, 默认的模板名称就是
blog/templates/blog/blog_index_page.html,我们在对应目录创建出这个文件,然后增加如下内容:

{% extends "base.html" %}
{% load wagtailcore_tags %}
{% block body_class %}template-blogindexpage{% endblock %}
{% block content %}
    

{{ page.title }}

{{ page.intro|richtext }}
{% for post in page.get_children %}

{{ post.title }}

{{ post.specific.intro }} {{ post.specific.body|richtext }} {% endfor %} {% endblock %}

大部分的内容我们应该已经很熟悉了,我们在稍后会解释get_children。注意pageurl标签,这个标签就类似Django的url标签,只是这里需要将Wagtail的page作为参数。

接下来就是创建出对应的页面。进入Wagtail的admin后台,创建BlogIndexPage,注意选择作为Homepage的下级页面, 同时确保在Promote属性页中的slug输入blog,然后发布(publish),正常情况我们可以正常访问
http://127.0.0.1:8000/blog/了。

这时候相信大家已经发现Wagtail与常规Django编程的差别了,那就是目前为止,我们没有用到MTV架构的View。

现在我们需要为Blog文章(BlogPage)创建model和模板,回到blog/models.py:

from django.db import models
from wagtail.models import Page
from wagtail.fields import RichTextField
from wagtail.admin.panels import FieldPanel
from 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"),
]

在上面的Model中,我们引入索引(index)使得这个model具有搜索功能,也就是说后面通过扩展首页的搜索功能,就可以按照文章进行搜索了,目前我们只需要将需要搜索的字段通过SearchField加入即可。修改好Model后运行:

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 %}

{{ page.title }}

{{ page.date }}

{{ page.intro }}
{{ page.body|richtext }}

Return to blog

{% endblock %}

注意这里使用Wagtail内置的方法get_parent()来获得当前Page的父节点的链接。

回到Admin管理员界面,我们为BlogIndexPage创建若干个子Page,Page的类型选择“Blog Page”。


Wagtail的Page管理十分强大,你可以在每个Page下面,创建任何类型的Page子页面。

把我们刚才添加的Page全部发布。这时候我们就完成了一个非常简单的Blog系统,通过访问/blog,我们可以看到类似这个界面:

博客文件标题应该可以链接到具体的博客文章页面,在具体的文章页面底部应该有一个返回到列表的链接。

父页面和子页面

在Wagtail中我们大部分的工作都围绕着树形结构这个概念开展,树形结构由节点和树叶组成,在这个例子中,BlogIndexPage就是一个节点,每一个BlogPage 的实例就是树叶。

再看一下blog_index_page.html一个重要的知识点:

{% for post in page.get_children %}

{{ post.title }}

{{ post.specific.intro }} {{ post.specific.body|richtext }} {% endfor %}

Wagtail中的每一个Page都可以调用它的父页面或子页面,为什么这里我们还明确要使用post.specific.intro而不直接用post.intro?我们来解释一下:

模板代码中get_children()方法会返回给我们一个Page实例列表,当我们想遍历Page实例中定义的属性的时候,我们是无法知道具体page实例是由哪个类创建的。所以Wagtail提供了specific方法,通过这个方法,可以感知Page实例的类是什么(在这里就是BlogPage),这样就可以按照BlogPage的实例去获得title和intro的值。也就是说我们需要 specific出来具体的类,然后访问实例的属性。这段比较难理解,实在不理解直接照葫芦画瓢先使用即可:)

为了让模板代码更具可读性(不出现specific),也可以使用with标签:

{% for post in page.get_children %}
{% with post=post.specific %}

{{ post.title }}

{{ post.intro }}

{{ 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()

重写(Overriding)Context

目前在我们的Blog列表中有几个问题:

  • 博客通常按时间倒序显示内容
  • 我们希望确保只显示已发布的内容。

为了完成这些事情,我们需要做的不仅仅是在模板中抓取索引页的子页面。我们希望的是修改模型定义中的查询集。Wagtail通过重写的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

我们在这里所做的就是检索原始上下文,创建一个自定义查询集,将其添加到检索到的上下文中,然后将修改后的上下文返回到视图中。之后我们还需要将blog_index_page.html中的{% for post in page.get_children %}

修改为{% for post in blogpages %}

现在试着取消发布你的一篇文章——它应该会从博客列表页面中消失。剩下的博客文章也应该是按照最新日期降序排列。

扫描二维码推送至手机访问。

版权声明:本文由ruisui88发布,如需转载请注明出处。

本文链接:http://www.ruisui88.com/post/2776.html

分享给朋友:

“Wagtail建站入门(二)” 的相关文章

vue项目-父页面数据变化使子页面更新的几种情况

当操作页面时候,特别是增删改操作之后,数据会有所改变,这个时候我们希望组件中的数据要和最新数据一致,就需要重新更新渲染。以下是针对几种不同情况下方式:一.子页面调用接口后重新渲染1.使用ref方式父组件中用ref=“xxx” 来声明子组件,然后通过在父组件值改变的地方来调用子组件中的方法this.$...

理解virt、res、shr之间的关系(linux系统篇)

前言想必在linux上写过程序的同学都有分析进程占用多少内存的经历,或者被问到这样的问题——你的程序在运行时占用了多少内存(物理内存)?通常我们可以通过top命令查看进程占用了多少内存。这里我们可以看到VIRT、RES和SHR三个重要的指标,他们分别代表什么意思呢?这是本文需要跟大家一起探讨的问题。...

身体越柔软越好?刻苦拉伸可能反而不健康 | 果断练

坐下伸直膝盖,双手用力向前伸,再用力……比昨天前进了一厘米,又进步了! 这么努力地拉伸,每个人都有自己的目标,也许是身体健康、线条柔美、放松肌肉、体测满分,也可能为了随时劈个叉,享受一片惊呼。 不过,身体柔软,可以享受到灵活的福利,也可能付出不稳定的代价,并不是越刻苦拉伸越好。太硬或者太软,都不安全...

高效使用 Vim 编辑器的 10 个技巧

在 Reverb,我们使用 MacVim 来标准化开发环境,使配对更容易,并提高效率。当我开始使用 Reverb 时,我以前从未使用过 Vim。我花了几个星期才开始感到舒服,但如果没有这样的提示,可能需要几个月的时间。这里有十个技巧可以帮助你在学习使用 Vim 时提高效率。1. 通过提高按键重复率来...

Acustica Audio 发布模拟Roland Jupiter 双声道合成器插件 TH2

福利: Acustica Audio 发布模拟Roland Jupiter 风格的双声道合成器插件 TH2 免费下载 意大利 Acustica Audio 公司发布布模拟Roland Jupiter 风格的双声道合成器插件 TH2 ,灵感来源于Acustica Audio的THING-8系列,它是...

虚幻引擎5.5发布

IT之家 11 月 13 日消息,虚幻引擎 5.5 现已发布。据介绍,新版本虚幻引擎在动画创作、虚拟制作和移动游戏开发方面取得进步;渲染、摄像机内视觉特效和开发人员迭代等领域的部分功能已可用于生产。IT之家整理部分功能亮点如下:动画Sequencer增强虚幻引擎的非线性动画编辑器 Sequencer...