项目总体简介请看用python搭建一个校园维基网站(一)。
本文可独立使用,创建了一个可编辑内容的首页,展示了wagtail的一些基础用法。文末为本文所创项目文件github地址。
比较详细,新手可尝试,不过最好有一定Django基础。
wagtail start genius
(pip install wagtail
安装依赖)创建名为genius
的工程文件夹,cd genius
进入目录。tree /a /f > 1.txt
在当前目录下生成1.txt
看到如下的项目结构。
E:. | manage.py | requirements.txt | +---genius | | urls.py | | wsgi.py | | __init__.py | | | +---settings | | base.py | | dev.py | | production.py | | __init__.py | | | +---static | | +---css | | | genius.css | | | | | /---js | | genius.js | | | /---templates | 404.html | 500.html | base.html | +---home | | models.py | | __init__.py | | | +---migrations | | 0001_initial.py | | 0002_create_homepage.py | | __init__.py | | | /---templates | /---home | home_page.html | /---search | views.py | __init__.py | /---templates /---search search.html
manage.py
是Django
项目通用的管理脚本(通过python manage.py 某命令参数
使用)。requirements.txt
用于存储当前项目的依赖列表(自动生成的为Django
和wagtail
,虚拟环境(virtualenv)下可用pip freeze >> requirements.txt
追加)。genius
包含项目主要信息,有主路由(urls.py
)、wsgi接口(wsgi.py
)、配置文件夹(分基础配置base.py
、开发环境配置dev.py
与生产环境配置production.py
,后二者依赖基础配置)、全局静态资源文件夹(static
)与模板资源文件夹(templates
)。home
是自动生成的app文件夹,包含了models.py
页面数据模型和templates
模板文件夹。默认生成的models.py
中定义了一个简单的HomePage
类(继承自wagtail
的Page
类)来代表一个页面(即默认的欢迎页)的模型(该简单模型的可编辑内容部分只有title
字段)。在wagtail
的概念中,页面模型和模板文件是默认关联的,如HomePage
默认对应的模板为templates/home/home_page.html
(注意命名的转换关系),而欢迎页http://127.0.0.1:8000
中的大部分内容就在该模板中(该模板使用extends
语句继承genius/templates/base.html
,并使用block
语句填充相应内容)。如下:
# 在命令行中先迁移数据库再启动服务,即可在本地查看欢迎页面 python manage.py migrate python manage.py runserver
search
则是自动生成的提供搜索功能的app文件夹,由于基于wagtail.wagtailsearch
所以只包含了views.py
视图文件和templates
模板文件夹。暂时不管。python manage.py flush
或者直接删除db.sqlite3
数据库文件。home
文件夹,新建一个名为wiki
的文件夹代表wiki
app,并将genius/settings/base.py
配置文件中第28行左右的INSTALLED_APPS
列表中的home
改为wiki
,以此来向配置文件注册我们的app。并在wiki
文件夹里添加目录和空文件:
/---wiki | models.py | __init__.py | +---migrations | __init__.py | /---templates /---wiki
我们的WikiHome
页面模型中需要图中红色高亮的一系列字段,其中title
字段继承自Page
类,不用额外添加,image
字段为连接到wagtailimages.Image
模型的外键。content_panels
列表提供了该页面模型在后台管理编辑页面的呈现内容。
此外,对于TopLink
和LittleIntros
我们需要另外新建两个继承wagtail
提供的Orderable
(使有序)的非页面模型。
WikiHomeLittleIntros
的字段有fontawesome图标类名,小标题和简述,如下图。还包含了一个wagtail
提供的对ForeignKey
进行了一层封装的ParentalKey
外键连接到它所属的WikiHome
页面。类似的,panels
表明出现在可编辑区。
WikiHomeTopLink
类似,为了层次上更清晰,采用了多重继承,在models.py
中只定义ParentalKey
外键,而在另一个文件中定义了RelatedLink
模型,包含的字段有链接文本和具体链接,只是具体链接可能为外链、某个页面或某个文档,占用了三个字段,此外还利用@property
装饰器为该模型添加了link
属性,来返回它的具体链接,这样在模板中就可以使用.link
调用。
综上,models.py
的内容为:
# -*- coding: utf-8 -*- from __future__ import absolute_import, unicode_literals from django.db import models from modelcluster.fields import ParentalKey from wagtail.wagtailcore.models import Page, Orderable from wagtail.wagtailadmin.edit_handlers import ( FieldPanel, InlinePanel) from wagtail.wagtailimages.edit_handlers import ImageChooserPanel from .umodels import RelatedLink # ------------------------主页------------------------- class WikiHome(Page): logoname = models.CharField( max_length=255, help_text=u"显示在左上角的网页名称" ) image = models.ForeignKey( 'wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+', help_text=u"大幅背景图" ) intro = models.TextField( blank=True, help_text=u"下方简单口号" ) content_panels = Page.content_panels + [ FieldPanel('logoname'), InlinePanel('toplinks', label="顶部右侧链接"), ImageChooserPanel('image'), FieldPanel('intro', classname="full"), InlinePanel('little_intros', label="下方一排推广简述"), ] class WikiHomeTopLink(Orderable, RelatedLink): page = ParentalKey('wiki.WikiHome', related_name='toplinks') class WikiHomeLittleIntros(Orderable): page = ParentalKey(WikiHome, related_name='little_intros') fa_name = models.CharField(blank=True, max_length=250, help_text=u'''FontAwesome图标类名 - 参考fontawesome.io/icons/''') title = models.CharField(blank=True, max_length=250, help_text=u"小标题") caption = models.CharField(blank=True, max_length=1000, help_text=u"简述") panels = [ FieldPanel('fa_name'), FieldPanel('title'), FieldPanel('caption'), ]
在models.py
旁新建umodels.py
文件供models.py
引用:
#--------------------------umodels.py----------------------------# from django.db import models from wagtail.wagtailadmin.edit_handlers import (FieldPanel, PageChooserPanel, MultiFieldPanel) from wagtail.wagtaildocs.edit_handlers import DocumentChooserPanel class LinkFields(models.Model): link_external = models.URLField("External link", blank=True) link_page = models.ForeignKey( 'wagtailcore.Page', null=True, blank=True, related_name='+' ) link_document = models.ForeignKey( 'wagtaildocs.Document', null=True, blank=True, related_name='+' ) @property def link(self): if self.link_page: return self.link_page.url elif self.link_document: return self.link_document.url else: return self.link_external panels = [ FieldPanel('link_external'), PageChooserPanel('link_page'), DocumentChooserPanel('link_document'), ] class Meta: abstract = True # Related links class RelatedLink(LinkFields): title = models.CharField(max_length=255, help_text="链接显示文本") panels = [ FieldPanel('title'), MultiFieldPanel(LinkFields.panels, "Link"), ] class Meta: abstract = True
templates/wiki/wiki_home.html
模板文件。它有一系列现成的layouts供我们使用,选择最适合本次主页的样式,查看源码可以得到详细的信息,在这里,为了简便,我们直接使用了该layout的额外样式表的链接(最好处理为本地的css样式文件,使用Django的static标签引用)。
对于模板来说,它对应的页面模型处于它的上下文环境,在模板中可以调用到该页面模型中的所有元素(使用Django的模板语言)。我们要按照页面排版将元素填充进去。
修改wiki_home.html
中内容如下:
{% extends "base.html" %} {% load wagtailcore_tags wagtailimages_tags %} {% block extra_css %} <link rel="stylesheet" href="https://unpkg.com/purecss@0.6.2/build/pure-min.css"> <link rel="stylesheet" href="https://unpkg.com/purecss@0.6.2/build/grids-responsive-min.css"> <link rel="stylesheet" href="https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css"> <link rel="stylesheet" href="https://purecss.io/combo/1.18.13?/css/layouts/marketing.css"> {% endblock %} {% block body_class %}wiki-homepage{% endblock %} {% block content %} <div class="header"> <div class="home-menu pure-menu pure-menu-horizontal pure-menu-fixed"> <a class="pure-menu-heading" href="">{{ page.logoname }}</a> <ul class="pure-menu-list"> <li class="pure-menu-item pure-menu-selected"><a href="{{ page.url }}" class="pure-menu-link" style="color:white">首页</a></li> {% for item in page.toplinks.all %} <li class="pure-menu-item"><a href="{{ item.link }}" class="pure-menu-link">{{ item.title }}</a></li> {% endfor %} </ul> </div> </div> {% image page.image original as image %} <div class="splash-container" style="background-image: url({{ image.url }}); background-size:cover"> <div class="splash"> <h1 class="splash-head" style="color: black">{{ page.title }}</h1> <p class="splash-subhead"> </p> <p> <form class="pure-form" action="/search"> <input type="text" name="query" placeholder="请在此输入搜索内容..."> <button type="submit" class="pure-button pure-button-primary">Get Started</button> </form> </p> </div> </div> <div class="content-wrapper"> <div class="content"> <h2 class="content-head is-center">{{ page.intro }}</h2> <div class="pure-g"> {% for item in page.little_intros.all %} <div class="l-box pure-u-1 pure-u-md-1-2 pure-u-lg-1-4"> <h3 class="content-subhead"> <i class="fa {{ item.fa_name }}"></i> {{ item.title }} </h3> <p> {{ item.caption }} </p> </div> {% endfor %} </div> </div> <div class="l-box-lrg pure-g" style="height:20px"> </div> {% load wiki_tags %} {% wikihome_footer %} </div> {% endblock %} {% block extra_js %} {% endblock %}
{% load wiki_tags %} {% wikihome_footer %}
还没有实现,它就是之前图中黄色框圈住的页脚了。考虑到页脚的内容一般比较固定,我们使用snippets和模板标签tag的形式来实现。它使得我们既可以在管理控制页面修改该页脚的内容,也使得页脚具有自己的一小段html模板,可以简便地被其它模板所调用。wiki
文件夹下的models.py
文件旁新建一个snippets.py
文件,添加如下内容:from wagtail.wagtailsnippets.models import register_snippet from django.db import models from wagtail.wagtailcore.fields import RichTextField from wagtail.wagtailadmin.edit_handlers import FieldPanel @register_snippet class FooterText(models.Model): body = RichTextField() panels = [ FieldPanel('body'), ] def __str__(self): return u"页面最底部文本 - 限单条" class Meta: verbose_name_plural = u'页面最底部文本'
实际上,它还是创建了一个Django模型,只包含了一个富文本字段,但是利用Wagtail
提供的register_snippet
装饰器我们可以简便地将其注册到管理界面,以便在管理界面修改。但是,还不能在模板中调用它,我们需要将它注册到Django的tag标签系统中,在wiki
目录下新建templatetags
文件夹,在该文件夹下新建wiki_tags.py
文件,添加如下内容。同样,借助简单的装饰器注册了该模板标签,且与wiki/tags/footer.html
片段模板绑定,并提供footer_text
作为上下文。
from django import template from wiki.snippets import FooterText register = template.Library() @register.inclusion_tag('wiki/tags/footer.html', takes_context=True) def wikihome_footer(context): footer_text = "" if FooterText.objects.first() is not None: footer_text = FooterText.objects.first().body return { 'footer_text': footer_text, }
然后就该创建对应的片段模板文件了。与上面代码中绑定的html文件路径对应,在wiki
app目录下新建templates/wiki/tags/footer.html
文件,添加如下内容:
{% load wagtailcore_tags %} <div class="footer l-box is-center"> {{ footer_text|richtext }} </div>
python manage.py makemigrations # 创建数据库迁移文件 python manage.py migrate # 执行数据库迁移 python manage.py createsuperuser # 创建超级管理员,邮箱随意 python manage.py runserver # 启动服务
http://127.0.0.1:8000/admin/
点击红圈部分来到如下图页面,删除默认页面。
确认删除后,选择在根目录下新建页面
这时便来到我们的创建的WikiHome模型的页面元素填写界面,依次填写后按红圈处Publish提交。
页面创建好后,我们需要将其挂载到站点上来正常显示,点击下图红框创建站点
如下图创建并保存,Root Page
选择新创建的页面。
最终,访问http://127.0.0.1:8000/ 便可以看到页面效果。
创建并保存