├── baidu_verify_kaObX83Nj0.html
├── getting_started
├── integrating_into_django.md
├── images
│ ├── tutorial_1.png
│ ├── tutorial_10.jpg
│ ├── tutorial_2.png
│ ├── tutorial_3.png
│ ├── tutorial_4a.png
│ ├── tutorial_4b.png
│ ├── tutorial_5.png
│ ├── tutorial_6.jpg
│ ├── tutorial_7.png
│ ├── tutorial_8.png
│ ├── tutorial_9.png
│ ├── wechat-pay.png
│ ├── drupal_content_type.png
│ └── a6x09981lks9yco3b8xcqf0.png
├── index.md
├── the_zen_of_wagtail.md
└── tutorial.md
├── advanced_topics
├── customisation
│ ├── extending_hallo.md
│ ├── images
│ │ ├── wechat-pay.png
│ │ ├── a6x09981lks9yco3b8xcqf0.png
│ │ ├── draftail_entity_stock_source.gif
│ │ └── draftail_entity_stock_rendering.png
│ ├── index.md
│ ├── custom_user_model.md
│ ├── admin_templates.md
│ ├── page_editing_interface.md
│ ├── rich_text_internals.md
│ └── extending_draftail.md
├── images
│ ├── wechat-pay.png
│ ├── images
│ │ ├── wechat-pay.png
│ │ └── a6x09981lks9yco3b8xcqf0.png
│ ├── a6x09981lks9yco3b8xcqf0.png
│ ├── animated_gifs.md
│ ├── index.md
│ ├── renditions.md
│ ├── custom_image_model.md
│ ├── feature_detection.md
│ └── image_serve_view.md
├── api
│ ├── images
│ │ ├── wechat-pay.png
│ │ └── a6x09981lks9yco3b8xcqf0.png
│ ├── v2
│ │ ├── images
│ │ │ ├── wechat-pay.png
│ │ │ └── a6x09981lks9yco3b8xcqf0.png
│ │ ├── configuration.md
│ │ └── usage.md
│ └── index.md
├── i18n
│ ├── images
│ │ ├── wechat-pay.png
│ │ └── a6x09981lks9yco3b8xcqf0.png
│ ├── duplicate_tree.md
│ └── index.md
├── documents
│ ├── images
│ │ ├── wechat-pay.png
│ │ └── a6x09981lks9yco3b8xcqf0.png
│ ├── index.md
│ └── custom_document_model.md
├── deploying.md
├── third_party_tutorials.md
├── settings.md
├── index.md
├── performance.md
├── jinja2.md
├── privacy.md
├── testing.md
└── embeds.md
├── images
├── wechat-pay.png
└── a6x09981lks9yco3b8xcqf0.png
├── topics
├── images
│ ├── wechat-pay.png
│ ├── image_filter_fill.png
│ ├── image_filter_max.png
│ ├── image_filter_min.png
│ ├── a6x09981lks9yco3b8xcqf0.png
│ ├── image_filter_fill_focal.png
│ └── image_filter_fill_focal_close.png
├── search
│ ├── images
│ │ ├── wechat-pay.png
│ │ └── a6x09981lks9yco3b8xcqf0.png
│ ├── index.md
│ ├── backends.md
│ ├── indexing.md
│ └── searching.md
├── index.md
├── permissions.md
├── writing_templates.md
├── snippets.md
├── images.md
└── pages.md
├── git-push.sh
├── .gitignore
├── book.json
├── SUMMARY.md
└── README.md
/baidu_verify_kaObX83Nj0.html:
--------------------------------------------------------------------------------
1 | kaObX83Nj0
--------------------------------------------------------------------------------
/getting_started/integrating_into_django.md:
--------------------------------------------------------------------------------
1 | # 将Wagtail集成到Django项目
2 |
3 |
4 |
--------------------------------------------------------------------------------
/advanced_topics/customisation/extending_hallo.md:
--------------------------------------------------------------------------------
1 | # 对 Hallo 编辑器进行扩展
2 |
3 | (略)。
4 |
--------------------------------------------------------------------------------
/images/wechat-pay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/images/wechat-pay.png
--------------------------------------------------------------------------------
/topics/images/wechat-pay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/topics/images/wechat-pay.png
--------------------------------------------------------------------------------
/images/a6x09981lks9yco3b8xcqf0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/images/a6x09981lks9yco3b8xcqf0.png
--------------------------------------------------------------------------------
/topics/images/image_filter_fill.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/topics/images/image_filter_fill.png
--------------------------------------------------------------------------------
/topics/images/image_filter_max.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/topics/images/image_filter_max.png
--------------------------------------------------------------------------------
/topics/images/image_filter_min.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/topics/images/image_filter_min.png
--------------------------------------------------------------------------------
/topics/search/images/wechat-pay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/topics/search/images/wechat-pay.png
--------------------------------------------------------------------------------
/advanced_topics/images/wechat-pay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/advanced_topics/images/wechat-pay.png
--------------------------------------------------------------------------------
/getting_started/images/tutorial_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/getting_started/images/tutorial_1.png
--------------------------------------------------------------------------------
/getting_started/images/tutorial_10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/getting_started/images/tutorial_10.jpg
--------------------------------------------------------------------------------
/getting_started/images/tutorial_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/getting_started/images/tutorial_2.png
--------------------------------------------------------------------------------
/getting_started/images/tutorial_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/getting_started/images/tutorial_3.png
--------------------------------------------------------------------------------
/getting_started/images/tutorial_4a.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/getting_started/images/tutorial_4a.png
--------------------------------------------------------------------------------
/getting_started/images/tutorial_4b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/getting_started/images/tutorial_4b.png
--------------------------------------------------------------------------------
/getting_started/images/tutorial_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/getting_started/images/tutorial_5.png
--------------------------------------------------------------------------------
/getting_started/images/tutorial_6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/getting_started/images/tutorial_6.jpg
--------------------------------------------------------------------------------
/getting_started/images/tutorial_7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/getting_started/images/tutorial_7.png
--------------------------------------------------------------------------------
/getting_started/images/tutorial_8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/getting_started/images/tutorial_8.png
--------------------------------------------------------------------------------
/getting_started/images/tutorial_9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/getting_started/images/tutorial_9.png
--------------------------------------------------------------------------------
/getting_started/images/wechat-pay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/getting_started/images/wechat-pay.png
--------------------------------------------------------------------------------
/advanced_topics/api/images/wechat-pay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/advanced_topics/api/images/wechat-pay.png
--------------------------------------------------------------------------------
/advanced_topics/i18n/images/wechat-pay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/advanced_topics/i18n/images/wechat-pay.png
--------------------------------------------------------------------------------
/topics/images/a6x09981lks9yco3b8xcqf0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/topics/images/a6x09981lks9yco3b8xcqf0.png
--------------------------------------------------------------------------------
/topics/images/image_filter_fill_focal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/topics/images/image_filter_fill_focal.png
--------------------------------------------------------------------------------
/advanced_topics/api/v2/images/wechat-pay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/advanced_topics/api/v2/images/wechat-pay.png
--------------------------------------------------------------------------------
/advanced_topics/images/images/wechat-pay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/advanced_topics/images/images/wechat-pay.png
--------------------------------------------------------------------------------
/advanced_topics/documents/images/wechat-pay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/advanced_topics/documents/images/wechat-pay.png
--------------------------------------------------------------------------------
/getting_started/images/drupal_content_type.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/getting_started/images/drupal_content_type.png
--------------------------------------------------------------------------------
/topics/images/image_filter_fill_focal_close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/topics/images/image_filter_fill_focal_close.png
--------------------------------------------------------------------------------
/topics/search/images/a6x09981lks9yco3b8xcqf0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/topics/search/images/a6x09981lks9yco3b8xcqf0.png
--------------------------------------------------------------------------------
/advanced_topics/images/a6x09981lks9yco3b8xcqf0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/advanced_topics/images/a6x09981lks9yco3b8xcqf0.png
--------------------------------------------------------------------------------
/getting_started/images/a6x09981lks9yco3b8xcqf0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/getting_started/images/a6x09981lks9yco3b8xcqf0.png
--------------------------------------------------------------------------------
/advanced_topics/customisation/images/wechat-pay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/advanced_topics/customisation/images/wechat-pay.png
--------------------------------------------------------------------------------
/advanced_topics/api/images/a6x09981lks9yco3b8xcqf0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/advanced_topics/api/images/a6x09981lks9yco3b8xcqf0.png
--------------------------------------------------------------------------------
/advanced_topics/i18n/images/a6x09981lks9yco3b8xcqf0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/advanced_topics/i18n/images/a6x09981lks9yco3b8xcqf0.png
--------------------------------------------------------------------------------
/advanced_topics/api/v2/configuration.md:
--------------------------------------------------------------------------------
1 | # Wagtail 编程接口第二版配置手册
2 |
3 |
4 | ## 基础配置
5 |
6 |
7 | ## 附加设置项
8 |
--------------------------------------------------------------------------------
/advanced_topics/api/v2/images/a6x09981lks9yco3b8xcqf0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/advanced_topics/api/v2/images/a6x09981lks9yco3b8xcqf0.png
--------------------------------------------------------------------------------
/advanced_topics/documents/index.md:
--------------------------------------------------------------------------------
1 | # 文档
2 |
3 | + [对文档模型进行定制](custom_document_model.md)
4 |
5 | - [对文档模型的引用](custom_document_model.md#module-wagtail.documents.models)
6 |
--------------------------------------------------------------------------------
/advanced_topics/images/images/a6x09981lks9yco3b8xcqf0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/advanced_topics/images/images/a6x09981lks9yco3b8xcqf0.png
--------------------------------------------------------------------------------
/advanced_topics/documents/images/a6x09981lks9yco3b8xcqf0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/advanced_topics/documents/images/a6x09981lks9yco3b8xcqf0.png
--------------------------------------------------------------------------------
/advanced_topics/customisation/images/a6x09981lks9yco3b8xcqf0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/advanced_topics/customisation/images/a6x09981lks9yco3b8xcqf0.png
--------------------------------------------------------------------------------
/advanced_topics/customisation/images/draftail_entity_stock_source.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/advanced_topics/customisation/images/draftail_entity_stock_source.gif
--------------------------------------------------------------------------------
/advanced_topics/customisation/images/draftail_entity_stock_rendering.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnu4cn/wagtailCMS-tutorial/HEAD/advanced_topics/customisation/images/draftail_entity_stock_rendering.png
--------------------------------------------------------------------------------
/git-push.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | git add .
3 |
4 | if [ "$1" = "" ]
5 | then
6 | echo "没有commit -m的输入,请输入commit -m内容,以[ENTER]结束:"
7 | read msg
8 | git commit -m "$msg"
9 | git push
10 | else
11 | git commit -m "$1"
12 | git push
13 | fi
14 |
--------------------------------------------------------------------------------
/advanced_topics/api/v2/usage.md:
--------------------------------------------------------------------------------
1 | # Wagtail编程接口第二版使用手册
2 |
3 | __目录__
4 |
5 |
6 |
7 | ## 获取内容
8 |
9 |
10 |
11 | ## 默认端点字段
12 |
13 |
14 |
15 | ## 自第一版后的改变
16 |
--------------------------------------------------------------------------------
/advanced_topics/images/animated_gifs.md:
--------------------------------------------------------------------------------
1 | # 动画GIF的支持
2 |
3 | Wagtail默认的图片库 Pillow, 并不支持动画的GIFs。
4 |
5 | 要获得动画GIF的支持,就必须[安装Wand](http://docs.wand-py.org/en/0.4.2/guide/install.html),Wand是一个到ImageMagick的绑定,所以要确保有安装ImageMagick程序。
6 |
7 | 在安装好了之后,Wagtail将自动使用Wand来对GIF文件进行调整,而仍然使用Pillow来调整其他图片。
8 |
--------------------------------------------------------------------------------
/advanced_topics/deploying.md:
--------------------------------------------------------------------------------
1 | # 部署Wagtail
2 |
3 | ## 在自己的服务器上
4 |
5 | Wagtail在现代基于Linux的发行版上的部署是直接了当的,但请查看[性能小节](performance.md)了解推荐的非Python服务。
6 |
7 | 当前偏好于Debian上的Nginx、Gunicorn与supervisor组合部署,不过Wagtail可与Django的[部署文档](https://docs.djangoproject.com/en/stable/howto/deployment/)中所介绍的全部组合运行起来。
8 |
9 | ## 在Divio云上
10 |
11 | ## 在 PythonAnywhere上
12 |
13 | ## 在其他PAASs 与 IAASs 上
14 |
15 | ## 部署技巧
16 |
17 | ### 关于静态文件
18 |
19 | ### 关于云存储
20 |
21 |
22 |
--------------------------------------------------------------------------------
/advanced_topics/images/index.md:
--------------------------------------------------------------------------------
1 | # 图片
2 |
3 | + [以Python方式生成图片的转写](renditions.md)
4 |
5 | + [动画GIF的支持](animated_gifs.md)
6 |
7 | + [对图片模型进行定制](custom_image_model.md)
8 |
9 | - [到图片模型的引用](custom_image_model.md#module-wagtail.images)
10 |
11 |
12 | + [特性侦测](feature_detection.md)
13 |
14 | - [设置](feature_detection.md#setup)
15 |
16 |
17 | + [动态地提供图片的试图](image_serve_view.md)
18 |
19 | - [设置](image_serve_view.md#setup)
20 | - [用法](image_serve_view.md#usage)
21 | - [高级配置](image_serve_view.md#advanced-configuration)
22 |
--------------------------------------------------------------------------------
/advanced_topics/api/index.md:
--------------------------------------------------------------------------------
1 | # Wagtail的编程接口
2 |
3 | API 模块提供了一个面向公众的、JSON 格式化的API,允许以原始字段数据形式获取到站点内容。此特性对于类似向非web客户端(比如移动应用)提供内容,以及抽取Wagtail站点内容为另一站点使用的情景下,是有用的。
4 |
5 | 请参阅 [RFC 8: Wagtail 编程借口](https://github.com/wagtail/rfcs/blob/master/text/008-wagtail-api.md#12---stable-and-unstable-versions) 了解有关 Wagtail 项目稳定政策的更多信息。
6 |
7 | + [Wagtail编程接口第二版配置手册](v2/configuration.md)
8 |
9 | - [基础配置](v2/configuration.md#basic-configuration)
10 | - [附加设置](v2/configuration.md#addtional-settings)
11 |
12 |
13 | + [Wagtail编程接口第二版使用手册](v2/usage.md)
14 |
15 | - [获取内容](v2/usage.md#fetching-content)
16 | - [默认端点字段](v2/usage.md#default-endpoint-fields)
17 | - [自第一版后的修改](v2/usage.md#changes-since-v1)
18 |
--------------------------------------------------------------------------------
/advanced_topics/customisation/index.md:
--------------------------------------------------------------------------------
1 | # 定制Wagtail
2 |
3 | + [定制编辑界面](page_editing_interface.md)
4 |
5 | - 对分页界面进行定制(the tabbed interface)
6 | - 关于富文本(HTML)
7 | - 对生成的表单进行定制
8 |
9 |
10 | + [富文本的内部元素](rich_text_internals.md)
11 |
12 | - 关于富文本的数据格式
13 | - 特效注册表
14 | - 对处理器进行重写
15 | - 对重写处理器进行注册
16 | - 关于编辑器小部件
17 | - 关于编辑器插件
18 | - 格式转换器
19 |
20 |
21 | + [对Draftail编辑器进行扩展](extending_draftail.md)
22 |
23 | - 创建新的内联样式
24 | - 创建新的块
25 | - 创建新的实体
26 | - Draftail小部件的集成
27 |
28 |
29 | + 对Hallo编辑器进行扩展
30 |
31 | - 对富文本元素的白名单操作
32 |
33 |
34 | + 对管理模板进行定制
35 |
36 | - 站点标志的定制(custom branding)
37 | - 在站点标志中指定某个站点或页面
38 | - 对登录表单进行扩展
39 | - 对客户端组件进行扩展
40 |
41 |
42 | + 对用户模型进行定制
43 |
44 | - 对用户表单进行定制的示例
45 |
--------------------------------------------------------------------------------
/advanced_topics/images/renditions.md:
--------------------------------------------------------------------------------
1 | # 以Python方式生成图片的转写
2 |
3 | 由Wagtail的`{% image %}`模板标签所生成的原始图片的渲染版本,被成为“转写(reditions)”,他们作为新的图片文件,在初次调用时,就存储在站点的`[media]/images`目录中了。
4 |
5 | 还可通过原生的`get_rendition()`方法,从Python动态地生成图片转写,比如:
6 |
7 | ```python
8 | newimage = myimage.get_rendition('fill-300x150|jpegquality-60')
9 | ```
10 |
11 | 在`myimage`的文件名为`foo.jpg`时,那么将生成一个名为`foo.fill-300x150.jpegquality-60.jpg`的该图片文件的新的转写,并保存到该站点的`[media]/images`目录。该方法的参数选项与模板标签`{% image %}`的过滤器规范一致,且应使用`|`进行分隔。
12 |
13 | 所生成的`Rendition`对象,将有着一些特定于该图片版本的属性,比如`url`、`width`及`height`等,因此类似于这些就可在某个API生成器中加以使用,比如:
14 |
15 | ```python
16 | url = myimage.get_rendition('fill-300x150|jpegquality-60').url
17 | ```
18 |
19 | 属于所生成转写的原始图片的那些参数,比如`title`,可通过该转写的`image`属性而访问到:
20 |
21 | ```sh
22 | >>> newimage.image.title
23 | 'Blue Sky'
24 | >>> newimage.image.is_landscape()
25 | True
26 | ```
27 |
28 | 另请参阅:[在模板中使用图片](../../topics/images.md#image-tag)
29 |
--------------------------------------------------------------------------------
/advanced_topics/third_party_tutorials.md:
--------------------------------------------------------------------------------
1 | # 一些第三方教程
2 |
3 | > __警告__ 下面的清单,是第三方开发者的一些教程与开发注解。其中的一些较早的链接,可能已不适应最新版的 Wagtail了。
4 |
5 |
6 | + [学习 Wagtail](https://learnwagtail.com/) -- 一些有关Wagtail方方面面的定期视频教程(2019年3月1日)
7 | + [Wagtail系列教程](https://www.accordbox.com/blog/wagtail-tutorials/) (2019年1月20日)
8 | + [致Django开发者的电子商务教程(带有 Wagtail 线上商店教程)](https://snipcart.com/blog/django-ecommerce-tutorial-wagtail-cms) (2018年7月5日)
9 | + [Wagtail 与 GraphQL](https://jossingram.wordpress.com/2018/04/19/wagtail-and-graphql/) (2018年4月19日)
10 | + [Wagtail 与 Azure 云存储的 blob 容器](https://jossingram.wordpress.com/2017/11/29/wagtail-and-azure-storage-blob-containers/) (2017年11月29日)
11 | + [使用 Twilio 同步技术、Django(包括 Wagtail)及 vue.js 来构建 TwilioQuest](https://www.twilio.com/blog/2017/11/building-twilioquest-with-twilio-sync-django-and-vue-js.html) (2017年11月6日)
12 | + [从Wagtail 1.0 升级到 Wagtail 1.1](https://www.caktusgroup.com/blog/2017/07/19/upgrading-wagtail/) (2017年7月19)
13 | + [Wagtail的多语种:一个用于演示如何实现多语种的简单项目](https://github.com/cristovao-alves/Wagtail-Multilingual) (2017年1月31日)
14 |
15 | [更多请参阅](http://docs.wagtail.io/en/v2.5.1/advanced_topics/third_party_tutorials.html)
16 |
--------------------------------------------------------------------------------
/topics/index.md:
--------------------------------------------------------------------------------
1 | # 使用手册
2 |
3 |
4 | + [页面模型](pages.md)
5 |
6 | - Wagtail页面模型示例
7 | - 编写页面模型
8 | - 模板渲染
9 | - 行内模型(Inline models)
10 | - 使用页面
11 | - 技巧
12 |
13 |
14 | + [编写页面模型](writing_templates.md)
15 |
16 | - 模板
17 | - 静态文件
18 | - 模板标签与过滤器
19 | - Wagtail的用户栏
20 | - 在上线前通过预览来验证输出
21 |
22 |
23 | + [在模板中使用图片](images.md)
24 |
25 | - 经由`img`标签实现更多的控制
26 | - `attrs`捷径
27 | - 在富文本中嵌入的图片
28 | - 图片输出格式
29 | - 背景色
30 | - JPEG图片的质量
31 |
32 |
33 | + [搜索功能](search/index.md)
34 |
35 | - 建立索引
36 | - 搜索
37 | - 搜索的后端
38 |
39 |
40 | + [内容块(Snippets)](snippets.md)
41 |
42 | - 内容的模型
43 | - 在模板标签中包含内容块
44 | - 将页面绑定到内容块
45 | - 令到内容块可被搜索
46 | - 给内容块打上标签
47 |
48 |
49 | + [使用`StreamField`特性得到格式自由的页面内容](streamfield.md)
50 |
51 | - 使用`StreamField`
52 | - 基础的块类型
53 | - 结构化的块类型
54 | - 示例:`PersonBlock`
55 | - 模板的渲染
56 | - `BoundBlocks`与值
57 | - `StructBlock`的定制编辑界面
58 | - `StructBlock`的定制值类(Custom value class for `StructBlock`)
59 | - 定制的块类型
60 | - 数据库的迁移
61 |
62 |
63 | + [权限](permissions.md)
64 |
65 | - 页面的权限
66 | - 图片/文档的权限
67 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | _book/*
9 |
10 | # Runtime data
11 | pids
12 | *.pid
13 | *.seed
14 | *.pid.lock
15 |
16 | # Directory for instrumented libs generated by jscoverage/JSCover
17 | lib-cov
18 |
19 | # Coverage directory used by tools like istanbul
20 | coverage
21 |
22 | # nyc test coverage
23 | .nyc_output
24 |
25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
26 | .grunt
27 |
28 | # Bower dependency directory (https://bower.io/)
29 | bower_components
30 |
31 | # node-waf configuration
32 | .lock-wscript
33 |
34 | # Compiled binary addons (https://nodejs.org/api/addons.html)
35 | build/Release
36 |
37 | # Dependency directories
38 | node_modules/
39 | jspm_packages/
40 |
41 | # Typescript v1 declaration files
42 | typings/
43 |
44 | # Optional npm cache directory
45 | .npm
46 |
47 | # Optional eslint cache
48 | .eslintcache
49 |
50 | # Optional REPL history
51 | .node_repl_history
52 |
53 | # Output of 'npm pack'
54 | *.tgz
55 |
56 | # Yarn Integrity file
57 | .yarn-integrity
58 |
59 | # dotenv environment variables file
60 | .env
61 |
62 |
--------------------------------------------------------------------------------
/advanced_topics/settings.md:
--------------------------------------------------------------------------------
1 | # Wagtail下对Django的配置
2 |
3 | 要从零开始安装Wagtail,就要创建一个Django项目,并在那个项目中建立一个应用。有关这些任务的教程,请参见[编写第一个Django应用](https://docs.djangoproject.com/en/stable/intro/tutorial01/)。项目的目录将像下面这样:
4 |
5 | ```sh
6 | myproject/
7 | myproject/
8 | __init__.py
9 | settings.py
10 | urls.py
11 | wsgi.py
12 | myapp/
13 | __init__.py
14 | models.py
15 | tests.py
16 | admin.py
17 | views.py
18 | manage.py
19 | ```
20 |
21 | 可安全地从应用目录中将`admin.py`与`views.py`移除,因为Wagtail将为模型提供到此功能。对Django进行加载Wagtail的配置,涉及将一些模块与变量加入到`settings.py`,以及将URL的配置加入到`urls.py`。请参考 [Django设置](https://docs.djangoproject.com/en/stable/topics/settings/)与[Django的URL调度器](https://docs.djangoproject.com/en/stable/topics/http/urls/),以获取对这些文件中定义了什么的全面了解。
22 |
23 | 下面的内容,是略过了许多的Django样板性设置的部分设置参考。如此时只想要尽快安装好Wagtail,而不想纠缠于这些设置,那么请参见[已准备好使用示例配置文件](#complete-example-config)。
24 |
25 |
26 | ## 关于中间件(`settings.py`)
27 |
28 |
29 | ## 关于应用(`settings.py`)
30 |
31 |
32 | ## 设置变量(`settings.py`)
33 |
34 | ## URL模式
35 |
36 |
37 | ## 已准备好使用示例配置文件
38 |
39 |
--------------------------------------------------------------------------------
/topics/search/index.md:
--------------------------------------------------------------------------------
1 | # 搜索功能
2 |
3 | Wagtail提供了全面且可扩展的搜索接口。此外,其还经由“站点编辑精选(Editor's Picks)”方式,提供提升搜索结果的方法。Wagtail还将一些有关通过搜索接口进行的查询的、简单统计数据收集了起来。
4 |
5 |
6 | + [建立索引](indexing.md)
7 |
8 | - [更新索引](indexing.md#updating-the-index)
9 | - [对额外字段进行索引](indexing.md#indexing-extra-fields)
10 | - [对定制模型建立索引](indexing.md#indexing-custom-models)
11 |
12 |
13 | + [进行搜索](searching.md)
14 |
15 | - [搜索的QuerySet](searching.md#searching-querysets)
16 | - [页面搜索视图示例](searching.md#an-example-page-search-view)
17 | - [提升后的搜索结果](searching.md#promoted-search-results)
18 |
19 |
20 | + [搜索后端](#backends)
21 |
22 | - [`AUTO_UPDATE`](backends.md#auto-update)
23 | - [`ATOMIC_REBUILD`](backends.md#atomic-rebuild)
24 | - [`BACKEND`](backends.md#backend)
25 |
26 |
27 | ## 索引的建立
28 |
29 | 必须首先将对象加入到搜索索引,那么这些对象才是可搜索的。而这涉及到那些想要进行索引的模型与字段的配置(索引正是对页面、图片与文档进行的),随后才是将这些对象插入到索引中。
30 |
31 | 请参阅[更新索引](#updating-the-index)部分,了解如何领导搜索索引中的对象,与数据库中的对象保持同步。
32 |
33 | 在`Page`或`Image`基类的子类中已创建了一些额外字段时,或许打算将这些新的字段加入到搜索索引,从而令到用户的搜索查询,可以与这些页面或图片的额外内容进行匹配。请参阅[对额外字段进行索引](#indexing-extra-fields)。
34 |
35 | 在有着不是从`Page`或`Image`基类派生的定制模型时,却又要令到其可搜索,那么请参阅[建立定制模型的索引](#indexing-custom-models)。
36 |
37 | ## 进行搜索
38 |
39 | Wagtail提供了用于在模型上完成搜索的一个API。同时还可以在Django QuerySets上进行搜索查询。
40 |
41 | 请参阅[进行搜索](#searching)。
42 |
43 |
44 | ## 关于后端
45 |
46 | Wagtail提供了为搜索索引的存储与完成搜索查询提供了三种后端:Elasticsearch、数据库,以及 PostgreSQL(需要Django >= 1.10)。也可运行自己的搜索后端。
47 |
48 | 请参阅 [关于搜索后端](backends.html)。
49 |
--------------------------------------------------------------------------------
/advanced_topics/documents/custom_document_model.md:
--------------------------------------------------------------------------------
1 | # 对文档模型进行定制
2 |
3 | 备用的`Document`模型,可用于添加定制的行为与额外字段。
4 |
5 | 要使用`Document`模型,需要完成以下步骤:
6 |
7 | + 创建出一个继承自`wagtail.documents.models.AbstractDocument`的新文档模型。那里就是要加入额外字段的地方。
8 | + 将`WAGTAILDOCS_DOCUMENT_MODEL`指向到该模型。
9 |
10 | 下面是一个示例:
11 |
12 | ```python
13 | # models.py
14 |
15 | from wagtail.documents.models import Document, AbstractDocument
16 |
17 | class CustomDocument(AbstractDocument):
18 | # 定制字段示例:
19 | source = models.CharField(
20 | max_length=255,
21 | # 下面两个参数必须进行设置,以允许Wagtail在上传时创建出一个文档实例
22 | blank=True,
23 | null=True
24 | )
25 |
26 | admin_form_fields = Document.admin_form_fields + (
27 | # 这里要加入所有定制字段的名称,以令到他们出现在表单中:
28 | 'source',
29 | )
30 | ```
31 |
32 | > **注意** 在定制文档模型上定义的那些字段,必须要么设置为非必须(`blank=True`),要么指定一个默认值。这是因为文档的上传与定制数据的输入是两个不同的动作。Wagtail需要在上传时能够立即创建出一条文档记录。
33 |
34 | 在应用设置模块中:
35 |
36 | ```python
37 | # 要确保将下面的 app_lebel,替换为之前把定制模型放入的那个应用
38 | WAGTAILDOCS_DOCUMENT_MODEL = 'app_lebel.CustomDocument'
39 | ```
40 |
41 | __从内建文档模型进行迁移__
42 |
43 | 在将某个既有站点修改为使用某个定制文档模型时,将不会自动拷贝原有文档到新的模型。这需要手动使用一个[数据迁移](https://docs.djangoproject.com/en/stable/topics/migrations/#data-migrations)来完成。
44 |
45 | 对内建文档模型进行引用的所有模板仍将如之前那样工作
46 |
47 | ## 对该定制文档模型的引用
48 |
49 |
50 | + `wagtail.documents.models.get_document_model()`
51 |
52 | 该方法从`WAGTAILDOCS_DOCUMENT_MODEL`设置获取到文档模型。在没有定义定制模型时,默认为标准的`Document`模型。
53 |
--------------------------------------------------------------------------------
/book.json:
--------------------------------------------------------------------------------
1 | {
2 | "author": "Translated by Peng Hailin, laxers@gmail.com",
3 | "description": "这是一本wagtail教程, python, Django, web, framework, 框架, 内容管理系统, CMS, Content Management System",
4 | "generator": "xfoss.com 网站",
5 | "links": {
6 | "sharing": {
7 | "weibo": null
8 | },
9 | "sidebar": {
10 | "Wagtail 教程": "https://wagtail.xfoss.com/"
11 | }
12 | },
13 | "pdf": {
14 | "fontSize": 12,
15 | "footerTemplate": null,
16 | "headerTemplate": null,
17 | "margin": {
18 | "bottom": 36,
19 | "left": 62,
20 | "right": 62,
21 | "top": 36
22 | },
23 | "pageNumbers": false,
24 | "paperSize": "a4"
25 | },
26 | "plugins" : [
27 | "highlight-code",
28 | "livereload",
29 | "lunr",
30 | "sharing",
31 | "fontsettings",
32 | "theme-comscore",
33 | "qrcode-list"
34 | ],
35 | "pluginsConfig": {
36 | "qrcode-list": {
37 | "title": "打尚&联系",
38 | "description": "如果您感觉有收获,欢迎给我打赏,以激励我输出更多的优质内容。",
39 | "except": ["谢谢你的支持"],
40 | "lists": [
41 | {
42 | "src": "./images/a6x09981lks9yco3b8xcqf0.png",
43 | "content": "支付宝",
44 | "alt": "支付宝"
45 | },
46 | {
47 | "src": "./images/wechat-pay.png",
48 | "content": "微信支付",
49 | "alt": "微信支付"
50 | }
51 | ]
52 | }
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/getting_started/index.md:
--------------------------------------------------------------------------------
1 | # 入门
2 |
3 | Wagtail 是构建于 [Django web 框架](https://www.djangoproject.com/) 之上的,因此本文档假定已经安装好了必要的软件包。如尚未安装这些软件包,那么就要安装以下必要的软件/程序:
4 |
5 | + [Python](https://www.python.org/downloads/)
6 | + [pip](https://pip.pypa.io/en/latest/installing.html)(请注意 `pip` 已默认包含在Python 3.4及以后的发布中)
7 |
8 |
9 | 同时建议使用 Virtualenv, 其提供了隔离的Python环境:
10 |
11 | + [Virtualenv](https://virtualenv.pypa.io/en/latest/installation.html)
12 |
13 |
14 | > **要点** 在安装 Wagtail 之前,有必要安装 `libjpeg` 与 `zlib` 两个库,他们提供了处理 JPEG、PNG 与 GIF 图像的支持(通过 Python 的`Pillow`库)。而安装这两个库的方式,则根据平台的不同而有所区别 -- 请参阅 Pillow 的 [特定平台安装说明](http://pillow.readthedocs.org/en/latest/installation.html#external-libraries)。
15 |
16 |
17 | 在安装了上述库之后,安装Wagtail的最快方式就是:
18 |
19 | *若使用了 Virtualenv, 那么请运行*
20 |
21 | ```sh
22 | $python3 -m venv .venv
23 | ```
24 |
25 | ```sh
26 | $ mkdir wagtail-demo && cd wagtail-demo
27 | $. ~/.venv/bin/activate
28 | $ pip install wagtail
29 | ```
30 |
31 | 在安装完毕后,Wagtail提供了一个类似于 Django 的 `django-admin startproject`命令,用于生成一个新的站点/项目(stubs out a new site/project):
32 |
33 | ```sh
34 | $ wagtail start demo
35 | ```
36 |
37 | 这将基于一个包含了满足起步所有需要的模板,而建立一个新的文件夹 `demo`。更多有关该模板的信息,请移步 [这里](getting_started/project_template.html)。
38 |
39 | 此时在 `demo` 文件夹中,只要运行一下对于所有Django项目来说都需要的必要几步:
40 |
41 | ```sh
42 | $ pip install -r requirements.txt
43 | $ ./manage.py migrate
44 | $ ./manage.py createsuperuser
45 | $ ./manage.py runserver
46 | ```
47 |
48 | 现在就可以在`http://localhost:8000`访问到该站点了,同时在`http://localhost:8000/admin`出可以访问到管理后端。
49 |
50 | 这些步骤建立起来一个新的单机化的Wagtail项目。如要将Wagtail加入到某个既有的Django项目,则请参阅[将Wagtail集成到Django项目中](getting_started/integrating_into_django.html)。
51 |
52 | 有一些可选`pip`包没有包含到默认安装,但推荐使用他们来提高性能或赋予Wagtail某些特性,包括:
53 |
54 | + [Elasticsearch](advanced_topics/performance.html)
55 | + [特性发现](advanced_topics/images/feature_detection.html)
56 |
--------------------------------------------------------------------------------
/advanced_topics/images/custom_image_model.md:
--------------------------------------------------------------------------------
1 | # 对图片模型进行定制
2 |
3 | `Image`模型可被定制,从而实现将额外字段添加到图片。
4 |
5 | 为了实现这个目的,需将以下两个模型添加到项目中:
6 |
7 | + 从`wagtail.images.models.AbstractImage`继承的图片模型本身。这就是要将额外字段进行添加的地方。
8 | + 从`wagtail.images.models.AbstractRendition`继承的转写模型。这用于存储新模型的转写。
9 |
10 |
11 | 以下是一个示例:
12 |
13 | ```python
14 | # models.py
15 | from django.db import models
16 |
17 | from wagtail.images.models import Image, AbstractImage, AdstractRendition
18 |
19 | class CustomImage(AbstractImage):
20 | # 在这里将所有额外字段添加到图片
21 |
22 | # 比如,要添加一个说明字段:
23 | # caption = models.CharField(max_length=255, blank=True)
24 |
25 | admin_form_fields = Image.admin_form_fields + (
26 | # 随后在这里添加字段名称,以令到其出现在表单中:
27 | 'caption',
28 | )
29 |
30 | class CustomRendition(AbstractRendition):
31 | image = models.ForeignKey(CustomImage, on_delete=models.CASACDE, related_name='renditions')
32 |
33 | class Meta:
34 | unique_together = (
35 | ('image', 'filter_spec', 'focal_point_key'),
36 | )
37 | ```
38 |
39 | > **注意** 在某个定制图片模型上定义的字段,必须要么设置为非要求的(`blank=True`),要么指定一个默认值 -- 这是因为图片的上传与定制数据的输入,是两个独立发生的事情,同时Wagtail需要能够在上传时立即创建出一条图片记录。
40 |
41 | 之后要将`WAGTAILIMAGES_IMAGE_MODEL`设置为指向该定制图片模型:
42 |
43 | ```python
44 | WAGTAILIMAGES_IMAGE_MODEL = 'images.CustomImage'
45 | ```
46 |
47 | __从内建图片模型进行迁移__
48 |
49 | __Migrating from the builtin image model__
50 |
51 | 在将某个既有站点更改为使用某种定制图片模型时,图片不会自动拷贝到新的模型。需要使用一个[数据迁移](https://docs.djangoproject.com/en/stable/topics/migrations/#data-migrations),来将原有图片拷贝到新的模型。
52 |
53 | 所有参考内建图片模型的模板,仍将之前那样继续工作,但要对其进行更新,才能观看到新的图片。
54 |
55 |
56 | ## 对定制图片模型的引用
57 |
58 |
59 | ### `wagtail.images.get_image_model()`
60 |
61 | 从`WAGTAILIMAGES_IMAGE_MODEL`设置取得图片模型。此方法对于那些制作Wagtail插件、需要图片模型的开发者有用。在没有定义定制模型时,默认为标准的`Image`模型。
62 |
63 |
64 |
65 | 获取图片模型的字符串形式的、带点的`app.Model`名称。对于制作Wagtail插件、需要对图片模型进行引用,比如在外键中,但又不需要模型本身的开发者有用。
66 |
--------------------------------------------------------------------------------
/advanced_topics/images/feature_detection.md:
--------------------------------------------------------------------------------
1 | # 特征识别
2 |
3 | __Feature Detection__
4 |
5 | Wagtail有着自动侦测面孔及图片中一些特征,并根据这些特征而对图片加以裁剪的能力。
6 |
7 | 特征识别特性,在图片上传时,使用OpenCV来识别图片中的面孔/特征。识别到的特征,作为`Image`模型上`focal_point_{x, y, width, height}`字段中的一个焦点,进行了内部保存(the detected features stored internally as a focal point in the `focal_point_{x, y, width, height}` fields on the `Image` model)。这些字段在图片于模板中被渲染时,为`fill`图片过滤器用来对图片进行裁剪。
8 |
9 | ## 设置
10 |
11 | 特征识别需要OpenCV,而OpenCV在安装时有点麻烦,因为其当前尚不支持`pip`的安装。
12 |
13 | ### 在Debian/Ubuntu上按照OpenCV
14 |
15 | Debian与Ubuntu提供了一个名为`python-opencv`的`apt-get`软件包:
16 |
17 | ```sh
18 | $ sudo apt-get install python-opencv python-numpy
19 | ```
20 |
21 | 这将把`PyOpenCV`安装到站点包中。在使用虚拟环境时,就要确保开启了站点包,否则Wagtail将不能导入`PyOpenCV`。
22 |
23 | ### 在虚拟环境中开启站点包
24 |
25 | __Enabling site packages in the virtual environment__
26 |
27 | 如未用到虚拟环境,那么可跳过此步骤。
28 |
29 | 站点包的开启,则会根据是否使用`pyvenv`(仅 Python 3.3以上版本),还是`virtualenv`来管理虚拟环境,而有所不同。
30 |
31 | + `pyvenv`
32 |
33 | 前往`pyvenv`目录并打开`pyvenv.cfg`文件,然后将`include-system-site-packages`设置为`true`。
34 |
35 |
36 | + `virtualenv`
37 |
38 | 前往虚拟环境目录并删除一个名为`lib/python-x.x/no-global-site-packages.txt`的文件。
39 |
40 | ## 对OpenCV安装进行测试
41 |
42 | 此时可通过打开一个Python命令行界面(在虚拟环境激活下),并进行下面的输入,对Wagtail是否能看到OpenCV进行测试:
43 |
44 | ```python
45 | import cv
46 | ```
47 |
48 | > **译者注** 这里尚需本地安装 `opencv-python` 包,通过 `pip install opencv-pyton`,并输入`import cv2`。
49 |
50 | 此时如没有看到`ImportError`,那么就算已经安装好了(如看到`libdc1394 error: Failed to initialize libdc1394`,这是无害的告警,可被忽略)。
51 |
52 | ### 在Wagtail中开启特征识别特性
53 |
54 | 一旦OpenCV安装好了,就需要将`WAGTAILIMAGES_FEATURE_DETECTION_ENABLED`设置为`True`:
55 |
56 | ```python
57 | # settings.py
58 |
59 | WAGTAILIMAGES_FEATURE_DETECTION_ENABLED = True
60 | ```
61 |
62 | ### 手动运行特征识别
63 |
64 | 特征识别是在有新的图片上传到Wagtail中时运行的。在站点中已有一些图片且想要在这些图片上运行特征识别时,就必须手动运行了。
65 |
66 | ```python
67 | from wagtail.images.models import Image
68 |
69 | for image in Image.objects.all():
70 | if not image.has_focal_point():
71 | image.set_focal_point(image.get_suggested_focal_point())
72 | image.save()
73 | ```
74 |
--------------------------------------------------------------------------------
/advanced_topics/index.md:
--------------------------------------------------------------------------------
1 | # 高级话题
2 |
3 | + [关于图片](images/index.md)
4 |
5 | - [用Python生成图片的转写](images/renditions.md)
6 | - [对动画GIF的支持](images/animated_gifs.md)
7 | - [对图片模型进行定制](images/custom_image_model.md)
8 | - [特性侦测](images/feature_detection.md)
9 | - [动态的图片提供视图](images/image_serve_view.md)
10 |
11 |
12 | + [关于文档](documents/index.md)
13 |
14 | - [对文档模型进行定制](documents/custom_document_model.md)
15 |
16 |
17 | + [嵌入的内容](embeds.md)
18 |
19 | - [在站点上嵌入内容](embeds.md#embedding-content-on-your-site)
20 | - [配置嵌入的 “查找器”(configuring embed "finders")](embeds.md#configuring-embed-finders)
21 |
22 |
23 | + [为Wagtail配置Django](settings.md)
24 |
25 | - [关于中间件(`settings.py`)](settings.md#middleware)
26 | - [关于应用(`settings.py`)](settings.md#apps)
27 | - [关于设置变量(`settings.py`)](settings.md#settings-variables)
28 | - [URL的模式](settings.md#url-patterns)
29 | - [准备好使用示例配置文件](settings.md#complete-example-config)
30 |
31 |
32 | + [Wagtail的部署](deploying.md)
33 |
34 | - 在自己的服务器上部署
35 | - 在 Divio 云上部署
36 | - 在 PythonAnywhere 上部署
37 | - 在其他 PAASs 与 IAASs 上部署
38 | - 部署技巧
39 |
40 |
41 | + [性能问题](performance.md)
42 |
43 | - 编辑界面
44 | - 公开用户
45 |
46 |
47 | + [国际化](i18n/index.md)
48 |
49 | - Wagtail 管理节目的翻译
50 | - 针对每名用户而改变Wagtail管理界面的语言
51 | - 修改Wagtail安装的主要语言
52 | - 创建带有多种语言的站点
53 |
54 |
55 | + [私有页面](privacy.md)
56 |
57 | - 设置一个登录页面
58 | - 设置一个全局的“需要口令”的页面
59 | - 为某种特定页面类型设置“需要口令”页面
60 |
61 |
62 | + [Wagtail的定制](customisation/index.md)
63 |
64 | - [对编辑界面进行定制](customisation/page_editing_interface.md)
65 | - [富文本内部](customisation/rich_text_internals.md)
66 | - 对Draftail编辑器进行扩展
67 | - 对Hallo编辑器进行扩展
68 | - 对管理界面模板进行定制
69 | - 对用户模型进行定制
70 |
71 |
72 | + [第三方教程](third_party_tutorials.md)
73 |
74 |
75 | + [Jinja2模板的支持](jinja2.md)
76 |
77 | - 对Django进行配置
78 | - 模板中的`self`
79 | - 模板的标签、函数与过滤器
80 |
81 |
82 | + [对Wagtail站点进行测试](testing.md)
83 |
84 | - WagtailPageTests
85 | - 表单数据助手
86 | - Fixtures
87 |
88 |
89 | + [Wagtail编程接口](api/index.md)
90 |
91 | - [Wagtail API 第二版 配置手册](api/configuration.md)
92 | - [Wagtail API 第二版使用手册](api/usage.md)
93 |
--------------------------------------------------------------------------------
/topics/permissions.md:
--------------------------------------------------------------------------------
1 | # 权限
2 |
3 | Wagtail采用并扩展了[Django权限系统](https://docs.djangoproject.com/en/stable/topics/auth/default/#topic-authorization),以满足网站内容创建的需求,诸如审批流程以及多个团队在某个站点(或在同一Wagtail安装下的多个站点)的不同区域上工作等等。经由Wagtail管理界面的“设置”下的“用户组(Group)”区域,可对权限进行配置。
4 |
5 | ## 页面的权限
6 |
7 | 在页面树的任何位置,都可将权限附加上去,并沿树向下传导。比如在某个站点有着这样的页面树时:
8 |
9 | ```sh
10 | MegaCorp/
11 | About us
12 | Offices/
13 | UK
14 | France
15 | Germany
16 | ```
17 |
18 | 随后某个有着在“Offices”页面有着“编辑”权限的组,将自动收到编辑“UK”、“France”与“Germany”页面的能力。通过将权限指派给“根”页面,便可全局地设置权限 -- 因为所有页面都必须存在于根节点之下,同时根是无法删除的,那么此项权限就会覆盖当前与未来存在的所有页面。
19 |
20 | 在某名用户经由Wagtail管理界面创建一个页面的时候,那名用户就被制定为其所创建页面的所有者了。有着“添加页面”权限的所有用户,都具有编辑其拥有页面的权限,以及添加新页面的权限。这是出于页面的创建,典型的就是一个涉及到创建一些草稿版本的迭代过程 -- 赋予用于创建草稿的能力,而不让他们进行接下来的编辑工作,是毫无用处的(this is in recognition of the fact that creating pages is typically an iterative process involving creating a number of draft versions -- giving a user the ability to create a draft but not letting them subsquently edit it would not be very useful)。能对某个页面进行编辑,也就意味着能删除该页面;与Django的标准权限模型不同,Wagtail中没有明显的“删除”权限。
21 |
22 | 完整的可用权限集如下:
23 |
24 | + `Add` -- 赋予创建此页面之下新的子页面的能力(提供了页面模型允许这一点 -- 请参阅[父页面/子页面类型规则](pages.html#parent-page-subpage-type-rules)),以及编辑与删除当前用户所有的页面的能力。除非用户还具有“发布”权限,那么已发布的页面是无法删除的。
25 |
26 | + `Edit` -- 授予对该页面,以及其下所有页面的编辑与删除能力,而无关页面的归属。仅有“编辑”权限的用户,是不能创建新页面的,只能对既有页面进行编辑。对于已发布的页面,除非该用户还有着“发布”权限,否则不能被删除。
27 |
28 | + `Publish` -- 授予对该页面和/或其子页面进行发布或撤回的能力。不具有发布权限的用户,无法直接对站点作出访问者可见的修改;而是必须将修改提交审核(这将发出一条通知给有着发布权限的用户)。发布权限与编辑权限是分开的;仅有发布权限的用户,将不能够进行任何编辑工作。
29 |
30 | + `Bulk delete` -- 允许用户以单次操作,删除一些有着后代页面的页面。如没有此种权限,那么就必须在删除父页面之前,先逐个地删除后代页面。这实际上是一种避免误删除的安全措施。`Bulk delete`必须与“添加”/“编辑”权限结合使用,因为他并未提供了到其本身的任何删除权力;他仅提供了一直该用户已具有的权限的“捷径”。比如,某名仅有着“添加”与“批量删除”权限的用户,将只能在受影响的页面属于那名用户,且这些页面处于尚未发布状态时,进行批量删除。
31 |
32 | + `Lock` -- 授予对该页面(及其下的所有页面)进行编辑锁定或解锁的能力,以阻止用户再对其进行任何的编辑。
33 |
34 | 对于草稿,只有在用户有着编辑或发布权限时,才能查看到。
35 |
36 | ## 图片/文档的权限
37 |
38 | 图片与文档的权限规则,在与页面类似的基础上运作。图片与文档被看着是由上传他们的用户“所有”;有着“添加”权限的用户,也具有对他们所拥有的图片/文档内容进行编辑的能力;删除则被看着是与编辑等同的,而非一种特别的权限类型。
39 |
40 | 对特定的一些图片与文档的访问,可通过设置 “ *集合(collections)* ”进行控制。默认所有图片与文档,都属于“根”集合,但可经由管理界面的 `Settings` -> `Collections` 区域,创建处新的集合。在“根”上设置的权限,适用于所有集合,因此某名具有在根上的图片的 “编辑” 权限的用户,就可对所有图片进行编辑;在其他集合上设置的权限,则只适用与那个集合了。
41 |
--------------------------------------------------------------------------------
/advanced_topics/performance.md:
--------------------------------------------------------------------------------
1 | # 性能问题
2 |
3 | Wagtail以速度为设计目标,体现在编辑器界面与前端上,但在想要更好的性能,或需要处理非常高的流量时,下面就是一些从安装中压榨更多性能的技巧。
4 |
5 | ## 编辑器界面的性能
6 |
7 | Wagtail开发者已经尽力将一个可以工作的Wagtail安装的外部依赖最小化了,目的就是令其尽可能简单的运作起来。尽管如此,仍可对一些默认设置进行配置,以获取更好的性能:
8 |
9 | ### 缓存方面
10 |
11 | 这里推荐使用 [Redis](http://redis.io/) 作为一个快速、持久的缓存。经由包管理器(在Debian或Ubuntu上:`sudo apt-get install redis-server`),并将`django-redis`添加到`requirements.txt`,且将其作为一个缓存后端进行开启:
12 |
13 | ```python
14 | CACHES = {
15 | 'default': {
16 | 'BACKEND': 'django_redis.cache.RedisCache',
17 | 'LOCATION': 'redis://127.0.0.1:6379/0',
18 | 'OPTIONS': {
19 | 'CLIENT_CLASS': 'django_redis.client.DefaultClient',
20 | 'PASSWORD': '+7xYeaxVbiR/Kkm+gv5p2LoSALRpRmzSCqMTRC2KE2D+gHiDf4/7Sdhx+mW/szMtwEgZH96ZIJKUPJj/',
21 | }
22 | }
23 | }
24 | ```
25 |
26 | ### 搜索方面
27 |
28 | Wagtail有着对 [Elasticsearch](http://www.elasticsearch.org/)很强的支持 -- 同时对编辑器界面与站点用户来说 -- 但在没有 Elasticsearch时也可回滚到数据库搜索。比起Django用于文本搜索的ORM,Elasticsearch更为快速且更为强大,因此推荐安装Elasticsearch,或者使用一个像是 [Searchly](http://www.searchly.com/)这样的托管服务。
29 |
30 | 更多有关配置Elasticsearch下的Wagtail的内容,请参见[Elasticsearch后端](../topics/search/backends.md#wagtailsearch-backends-elasticsearch)。
31 |
32 | ### 数据库方面
33 |
34 | Wagtail在PostgreSQL、SQLite与MySQL上进行过测试。他也应工作在一些第三方数据库后端上(MS SQL已知可以工作但未进行测试)。这里推荐使用PostgreSQL作为生产用途。
35 |
36 | ## 模板方面
37 |
38 | 读取与编译模板方面的压力可能叠加起来。在某些情形下可通过使用 [Django带有缓存的模板加载器](https://docs.djangoproject.com/en/stable/ref/templates/api/#django.template.loaders.cached.Loader),而获取到显著的性能提升:
39 |
40 | ```python
41 | TEMPLATES = [{
42 | 'BACKEND': 'django.template.backends.django.DjangoTemplates',
43 | 'DIR': [os.path.join(BASE_DIR, 'templates')],
44 | 'OPTIONS': {
45 | 'loaders': [
46 | ('django.template.loaders.cached.Loader', [
47 | 'django.template.loaders.filesystem.Loader',
48 | 'django.template.loaders.app_directories.Loader',
49 | ])
50 | ]
51 | }
52 | }]
53 | ```
54 |
55 | 但对使用此种加载器有一个注意事项。一旦模板被缓存起来,那么对模板文件的修改将不会生效。这就意味着 *不* 应在开发环境使用此加载器。
56 |
57 | ## 对于公开用户
58 |
59 | ### 缓存的代理服务器
60 |
61 | 为了支持有着出色响应时间的海量流量,推荐使用某种缓存代理方案。在生产中已对 [Vanish](http://www.varnish-cache.org/) 与 [Squid](http://www.squid-cache.org/) 进行过测试。像是 [Cloudflare](https://www.cloudflare.com/)一类的托管代理也应可以工作。
62 |
63 | Wagtail有着Vanish/Squid上自动缓存失效的支持。请参阅[前端缓存无效化](reference/contrib/frontendcache.md#frontend-cache-purging)。
64 |
--------------------------------------------------------------------------------
/advanced_topics/customisation/custom_user_model.md:
--------------------------------------------------------------------------------
1 | # 定制用户模型
2 |
3 | ## 用户表单定制示例
4 |
5 | 本示例对如何将一个文本字段与外键,添加到某个定制的用户模型,及将Wagtail的用户表单配置为允许对这些字段进行更新进行了演示。
6 |
7 | 创建出一个定制用户模型。在此情形下,这里对`AbstractUser`类进行了扩展,并添加了两个字段。这里的外键引用了另一个模型(并未给出)。
8 |
9 | ```python
10 | class User(AbstractUser):
11 | country = models.CharField(verbose_name='国家', max_length=255)
12 | status = models.ForeignKey(MembershipStatus, on_delete=models.SET_NULL, null=True, default=1)
13 | ```
14 |
15 | 将包含了这个用户模型的应用,添加到 `INSTALLED_APPS` 并将 `AUTH_USER_MODEL` 设置为对该模型的应用。在本示例中,应用名为 `users` 同时模型为 `User`
16 |
17 | ```python
18 | AUTH_USER_MODEL = 'users.USER'
19 | ```
20 |
21 | 在应用中创建出定制的用户 `create` 与 `edit` 表单:
22 |
23 | ```python
24 | from django import forms
25 | from django.utils.translation import ugettext_lazy as _
26 |
27 | from wagtail.users.forms import UserEditForm, UserCreationForm
28 |
29 | class CustomUserEditForm(UserEditForm):
30 | contry = forms.CharField(required=True, label=_("Country"))
31 | status = forms.ModelChoiceField(queryset=MembershipStatus.objects, required=True, label=_("Status"))
32 |
33 | class CustomUserCreationForm(UserCreationForm):
34 | country = forms.CharField(required=True, label=_("Country"))
35 | status = forms.ModelChoiceField(queryset=MembershipStatus.objects, required=True, label=_("Status"))
36 | ```
37 |
38 | 对Wagtail的用户 `create` 与 `edit` 模板加以扩展。这些扩展的模板应放在模板目录`wagtailusers/users`下。
39 |
40 | 模板 `create.html`:
41 |
42 | {% raw %}
43 |
44 | {% extends "wagtailusers/users/create.html" %}
45 |
46 | {% block extra_fields %}
47 | {% include "wagtailadmin/shared/field_as_li.html" with field=form.country %}
48 | {% include "wagtailadmin/shared/field_as_li.html" with field=form.status %}
49 | {% endblock %}
50 | {% endraw %}
51 |
52 |
53 | 模板 `edit.html`:
54 |
55 | {% raw %}
56 |
57 | {% extends "wagtailusers/users/edit.html" %}
58 |
59 | {% block extra_fields %}
60 | {% include "wagtailadmin/shared/field_as_li.html" with field=form.country %}
61 | {% include "wagtailadmin/shared/field_as_li.html" with field=form.status %}
62 | {% endblock %}
63 | {% endraw %}
64 |
65 |
66 | 这里的 `extra_fields` 块允许将一些字段插入到默认模板中的 `last_name` 字段下面。有一些其他块的覆写选项,允许将一些字段追加到既有字段的末尾或开头,或是允许对所有字段进行重新定义。
67 |
68 | 将下面这些 Wagtail 设置项添加到项目,以对这些用户表单附加项进行引用:
69 |
70 | ```python
71 | WAGTAIL_USER_EDIT_FORM = 'users.forms.CustomUserEditForm'
72 | WAGTAIL_USER_CREATION_FORM = 'users.forms.CustomUserCreationForm'
73 | WAGTAIL_USER_CUSTOM_FIELDS = ['country', 'status']
74 | ```
75 |
--------------------------------------------------------------------------------
/SUMMARY.md:
--------------------------------------------------------------------------------
1 | # 目录
2 |
3 | * [Wagtail 内容管理系统 CMS 教程](README.md)
4 |
5 | * [入门](getting_started/index.md)
6 |
7 | * [第一个Wagtail站点](getting_started/tutorial.md)
8 | * [将Wagtail集成到现有的Django项目](getting_started/integrating_into_django.md)
9 | * [Wagtail之禅](getting_started/the_zen_of_wagtail.md)
10 |
11 | * [使用手册](topics/index.md)
12 |
13 | * [关于页面模型](topics/pages.md)
14 | * [编写模板](topics/writing_templates.md)
15 | * [在模板中使用图片](topics/images.md)
16 | * [搜索功能](topics/search/index.md)
17 | * [建立索引](topics/search/indexing.md)
18 | * [进行搜索](topics/search/searching.md)
19 | * [搜索后端](topics/search/backends.md)
20 | * [内容片段](topics/snippets.md)
21 | * [使用`StreamField`特性的自由格式页面内容](topics/streamfield.md)
22 | * [权限问题](topics/permissions.md)
23 |
24 | * [高级话题](advanced_topics/index.md)
25 |
26 | * [图片](advanced_topics/images/index.md)
27 | * [以Python方式生成图片的转写](advanced_topics/images/renditions.md)
28 | * [动画GIF的支持](advanced_topics/images/animated_gifs.md)
29 | * [对图片模型进行定制](advanced_topics/images/custom_image_model.md)
30 | * [特性侦测](advanced_topics/images/feature_detection.md)
31 | * [动态地提供图片的视图](advanced_topics/images/image_serve_view.md)
32 | * [文档](advanced_topics/documents/index.md)
33 | * [对文档模型进行定制](advanced_topics/documents/custom_document_model.md)
34 | * [关于嵌入内容](advanced_topics/embeds.md)
35 | * [Wagtail下对Django的配置](advanced_topics/settings.md)
36 | * [部署Wagtail](advanced_topics/deploying.md)
37 | * [性能问题](advanced_topics/performance.md)
38 | * [国际化问题](advanced_topics/i18n/index.md)
39 | * [创建多语言站点(通过复制页面树的方式)](advanced_topics/i18n/duplicate_tree.md)
40 | * [私有页面](advanced_topics/privacy.md)
41 | * [定制Wagtail](advanced_topics/customisation/index.md)
42 | * [编辑接口的定制](advanced_topics/customisation/page_editing_interface.md)
43 | * [关于富文本内部元素](advanced_topics/customisation/rich_text_internals.md)
44 | * [对Draftail编辑器的扩展](advanced_topics/customisation/extending_draftail.md)
45 | * [对Hallo编辑器的扩展](advanced_topics/customisation/extending_hallo.md)
46 | * [管理模板的定制](advanced_topics/customisation/admin_templates.md)
47 | * [对用户模型进行定制](advanced_topics/customisation/custom_user_model.md)
48 | * [第三方教程](advanced_topics/third_party_tutorials.md)
49 | * [Jinja2模板的支持](advanced_topics/jinja2.md)
50 | * [对 Wagtail 站点进行测试](advanced_topics/testing.md)
51 | * [Wagtail的编程接口](advanced_topics/api/index.md)
52 | * [Wagtail编程接口第二版配置手册](advanced_topics/api/v2/configuration.md)
53 | * [Wagtail编程接口第二版使用手册](advanced_topics/api/v2/usage.md)
54 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Wagtail教程
2 |
3 | 你可以直接在 xfoss.com 阅读本书:[wagtail.xfoss.com](https://wagtail.xfoss.com/)。xfoss.com 还有其他书籍:
4 |
5 | + [60天通过CCNA考试](https://ccna60d.xfoss.com),一本基础的网络通讯书,翻译自国外经典 CCNA 60 days
6 | + [TypeScript 手册](https://ts.xfoss.com/),一本TypeScript的入门书籍,翻译自 TypeScript官方网站
7 |
8 |
9 | 你可以在 https://github.com/gnu4cn/wagtailCMS-tutorial 对本项目进行 fork, 并提交你的修正。
10 |
11 | Wagtail是一套以 Python 编写的、构建於 Django web框架之上的开放源代码内容管理系统。
12 |
13 | 本教程由以下章节构成,希望在学习这些内容后,能对其有全面掌握与切实使用。
14 |
15 | + 初步
16 | - [入门](getting_started/index.md)
17 | - [第一个Wagtail站点](getting_started/tutorial.md)
18 | - 演示网站
19 |
20 | + [使用Wagtail](topics/index.md)
21 | - [关于页面模型](topics/pages.md)
22 | - [编写模板](topics/writing_templates.md)
23 | - [在模板中使用图片](topics/images.md)
24 | + [搜索功能](topics/search/index.md)
25 | - [建立索引](topics/search/indexing.md)
26 | - [进行搜索](topics/search/searching.md)
27 | - [关于搜索后端](topics/search/backends.md)
28 | - [第三方教程](advanced_topics/third_party_tutorials.md)
29 |
30 | + 致内容编辑者
31 | - 内容编辑者指南
32 |
33 | ## 索引
34 |
35 |
36 | + [入门](getting_started.md)
37 |
38 | - [第一个Wagtail站点](getting_started/tutorial.md)
39 | - 演示站点
40 | - 将 Wagtail集成到某个Django项目
41 | - [Wagtail哲學](getting_started/the_zen_of_wagtail.md)
42 |
43 |
44 | + [使用手册](topics/index.md)
45 |
46 | - [页面模型](topics/pages.md)
47 | - [编写模板](topics/writing_templates.md)
48 | - [在模板中使用图片](topics/images.md)
49 | - [搜索功能](topics/search/index.md)
50 | - [内容片段](topics/snippets.md)
51 | - [使用 StreamField 的自由格式页面内容](topics/streamfield.md)
52 | - [权限相关](topics/permissions.md)
53 |
54 |
55 | + [高级话题](advanced_topics/index.md)
56 |
57 | - [图片](advanced_topics/images/index.md)
58 | - [文档](advanced_topics/documents/index.md)
59 | - [嵌入的内容](advanced_topics/embeds.md)
60 | - [Wagtail下Django的配置](advanced_topics/settings.md)
61 | - [Wagtail的部署](advanced_topics/deploying.md)
62 | - [性能问题](advanced_topics/performance.md)
63 | - [国际化](advanced_topics/i18n/index.md)
64 | - [私有页面](advanced_topics/privacy.md)
65 | - [定制Wagtail](advanced_topics/customisation/index.md)
66 | - [第三方教程](advanced_topics/third_party_tutorials.md)
67 | - [Jinja2 模板的支持](advanced_topics/jinja2.md)
68 | - [对Wagtail站点进行测试](advanced_topics/testing.md)
69 | - [Wagtail编程接口](advanced_topics/api/index.md)
70 |
71 |
72 | + 参考文档
73 |
74 | - 页面
75 | - 贡献模块
76 | - 管理命令
77 | - 钩子
78 | - 信号
79 | - 项目模板
80 |
81 |
82 | + 支持
83 |
84 |
85 | + Wagtail的使用:内容编辑手册
86 |
87 | - 简介
88 | - 入门
89 | - 找到你自己的方式
90 | - 建立新的页面
91 | - 编辑既有页面
92 | - 对文档或图片进行管理
93 | - 对重定向进行管理
94 | - 管理员的任务
95 | - 浏览器问题
96 |
97 |
98 | + 贡献到Wagtail
99 |
100 | - 问题追踪
101 | - 开发
102 | - 提交代码
103 | - 用户节目样式手册
104 | - 一般代码编写指南
105 | - Python代码编写指南
106 | - CSS 代码编写指南
107 | - JavaScript代码编写指南
108 | - Wagtail的发布流程
109 |
--------------------------------------------------------------------------------
/advanced_topics/jinja2.md:
--------------------------------------------------------------------------------
1 | # Jinja2 模板的支持
2 |
3 | Wagtail支持 Jinja2 模板的全部前端特性。更多有关以下模板标签的信息,可在 [编写模板](https://wagtail.xfoss.com/topics/writing_templates.md#writing_templates) 文档中找到。
4 |
5 | ## 对Django进行配置
6 |
7 | 需要对 Django 进行配置,以支持到 Jinja2 模板。因为 Wagtail 的管理界面是以常规 Django 模板进行编写的,因此就必须将Django配置为同时使用两张模板引擎。请将下面的配置添加到应用的 `TEMPLATE` 设置项:
8 |
9 | ```python
10 | TEMPLATES = [
11 | # ...
12 |
13 | {
14 | 'BACKEND': 'django.template.backends.jinja2.Jinja2',
15 | 'APP_DIRS': True,
16 | 'OPTIONS': {
17 | 'extensions': [
18 | 'wagtail.core.jinja2tags.core',
19 | 'wagtail.admin.jinja2tags.userbar',
20 | 'wagtail.images.jinja2tags.images',
21 | ]
22 | }
23 | }
24 | ]
25 | ```
26 |
27 | Jinja 的模板,必须放在应用的 `jinja2/` 目录中。比如`events` 应用中的 `EventPage` 模型的模板,就应被创建于 `events/jinja2/events/event_page.html`。
28 |
29 | 默认下,Jinja 的环境并没有任何的 Django 函数或过滤器。Django文档中有着有关 [为 Django 而对 Jinja 进行配置](https://docs.djangoproject.com/en/stable/topics/templates/#django.template.backends.jinja2.Jinja2)的更多信息。
30 |
31 | ## 模板中的 `self`
32 |
33 | 在 Django 的模板中,`self` 可用于对当前页面、流式块(stream block)或字段面板进行引用。但在 Jinja 中,`self`则是保留作内部用途的。在编写Jinja模板时,使用 `page` 来引用页面,使用`value`来引用流式块,同时使用`field_panel`来引用字段面板。
34 |
35 |
36 | ## 模板标签、函数与过滤器
37 |
38 | + `pageurl()`
39 |
40 | 生成某个页面实例的URL:
41 |
42 | ```html
43 | 更多信息
44 | ```
45 |
46 | 请参考 [`pageurl`](https://wagtail.xfoss.com/topics/writing_templates.md#pageurl-tag) 了解更多信息。
47 |
48 | + `slugurl()`
49 |
50 | 生成某个带有别名的页面(a Page with a slug)的URL:
51 |
52 | ```html
53 | 关于我们
54 | ```
55 |
56 | 请参考 [`slugurl`](https://wagtail.xfoss.com/topics/writing_template.md#slugurl-tag) 了解更多信息。
57 |
58 | + `image()`
59 |
60 | 对某个图片进行缩放,并输出一个 `` 标签:
61 |
62 | ```html
63 | {# 输出一个图片标签 #}
64 | {{ image(page.header_image), "fill-1024x200", class="header-image" }}
65 |
66 | {# 缩放某个图片 #}
67 | {% set background=image(page.background_image, "max-1024x1024") %}
68 |
需要口令来访问此页面。
68 | 84 | 85 | 86 | ``` 87 | 88 | 文档上的口令限制,使用另外的模板,经由`DOCUMENT_PASSWORD_REQUIRED_TEMPLATE`设置项加以指定;该模板也将接收到上面讲到的`form`与`action_url`上下文变量。 89 | 90 | ## 设定特定页面类型的“需要口令”页面 91 | 92 | 可在页面模型上定义`password_required_template`属性,以使用仅在那个页面类型下、“需要口令”视图的定制模板。比如,某个站点有着一个用于与描述文字一道,显示嵌入视频的页面类型,该页面类型可能要使用定制的、通常需要展示视频描述文字,但又是在原本放置嵌入视频的地方,展示口令表单的“需要口令”模板: 93 | 94 | ```python 95 | class VideoPage(Page): 96 | ... 97 | 98 | password_required_template = 'video/password_required.html' 99 | ``` 100 | -------------------------------------------------------------------------------- /advanced_topics/images/image_serve_view.md: -------------------------------------------------------------------------------- 1 | # 动态的图片提供视图 2 | 3 | __Dynamic image serve view__ 4 | 5 | 在多数场合,想要在Python中生成图片副本的开发者,都应使用`get_rendition()`方法,请参考[以Python方式生成图片转写](renditions.md)。 6 | 7 | 在需要为某种诸如博客或移动应用这样的 _外部_ 系统生成图片的一些版本时,Wagtail提供了一种通过调用独特的URL,来动态生成图片副本的视图。 8 | 9 | 此种视图获取到URL中的图片id、过滤器规范与安全性签名。在这些参数为有效的情况下,将提供一个符合条件的图片文件。 10 | 11 | 与`{% image %}`标签一样,该图片副本是在第一次调用时生成的,后续调用将从缓存中予以提供。 12 | 13 | ## 设置 14 | 15 | 将该视图的一个条目,添加到站点URLs配置中: 16 | 17 | ```python 18 | # app/urls.py 19 | 20 | from wagtail.images.views.serve import ServeView 21 | 22 | urlpatterns = [ 23 | ... 24 | 25 | url(r'^images/([^/]*)/(\d*)/([^/]*)/[^/]*$', ServeView.as_view(), name='wagtailimages_serve'), 26 | 27 | ... 28 | 29 | # 确保该 wagtailimages_serve 行,出现在默认Wagtail页面服务路由之上 30 | # Ensure that the wagtailimages_serve line appears above the default Wagtail page serving route 31 | 32 | url(r'', include(wagtail_urls)), 33 | ] 34 | ``` 35 | 36 | ## 用法 37 | 38 | ### 图片URL生成器的UI 39 | 40 | 在开启了动态提供图片特性之后,在管理界面中的图片URL生成器将自动变为可用。可经由任意图片的编辑页面,通过点击右侧的“URL生成器”按钮,访问到图片URL生成器。 41 | 42 | 该界面令到站点编辑可以生成到图片裁剪版本的URLs。 43 | 44 | ### 以Python方式,生成动态的图片URLs 45 | 46 | 也可使用Python代码来生成动态的图片URLs,并经由API加以提供,或直接在模板中进行使用。 47 | 48 | 在模板中使用动态的图片URLs的一个优势,就是在渲染时不会像`{% image %}`标签那样阻塞到初次响应。 49 | 50 | `wagtail.images.views.serve`中的`generate_image_url`函数,是生成动态的图片URL的一种方便的方法。 51 | 52 | 下面是在某个视图中该函数的使用示例: 53 | 54 | ```python 55 | def display_image(request, image_id): 56 | image = get_object_or_404(Image, id=image_id): 57 | 58 | return render(request, 'display_image.html', { 59 | 'image_url': generated_image_url(image, 'fill-100x100') 60 | }) 61 | ``` 62 | 63 | 对图片的操作,可通过将这些操作以`|`字符连接起来的方式,链接起来: 64 | 65 | ```python 66 | return render(request, 'display_image.html', { 67 | 'image_url': generate_image_url(image, 'fill-100x100|jpegquality-40') 68 | }) 69 | ``` 70 | 71 | 在模板中: 72 | 73 | {% raw %} 74 | 75 | {% load wagtailimages_tags %} 76 | ... 77 | 78 | 79 | {% image_url page.photo "width-400" %} 80 | 81 | 82 | {% image_url page.photo "fill-100x100|jpegquality-40" %} 83 | 84 | 85 | {% image_url page.photo "width-400" "mycustomview_serve" %} 86 | {% endraw %} 87 | 88 | 可传递一个将用于经由其提供图片的可选视图名称。默认的视图名称为`wagtailimages_serve`。 89 | 90 | ## 高级配置 91 | 92 | ### 令到视图重定向而非直接提供 93 | 94 | __Making the view redirect instead of serve__ 95 | 96 | 默认下该视图将直接提供图片文件。此行为可修改为一个`301`重定向,在图片留存于外部主机时,这样做会有用处。 97 | 98 | 要开启重定向,就要在urls配置中,将`action='redirect'`传递给`ServeView.as_view()`方法: 99 | 100 | ```python 101 | from wagtail.images.views.serve import ServeView 102 | 103 | urlpatterns = [ 104 | ... 105 | 106 | url(r'^images/([^/*])/(\d*)/[^/*]/[^/]*$', ServeView.as_view(action='redirect'), name='wagtailimages_serve'), 107 | ] 108 | ``` 109 | 110 | ### 与`django-sendfile`的集成 111 | 112 | [`django-sendfile`](https://github.com/johnsensible/django-sendfile) 可将图片数据传输工作交给web服务器,而不是直接由Django应用直接提供图片数据。在站点有着很多同时被下载的图片,却又无法使用[带有缓存的代理服务器](performance.md#caching-proxy)或CDN的情况下,这样做可极大地减低服务器负载。 113 | 114 | 首先要安装和配置好`django-sendfile`,并将web服务器配置好使用`django-sendfile`。如尚未准备好这些,请参考该[安装文档](https://github.com/johnsensible/django-sendfile#django-sendfile)。 115 | 116 | 可使用`SenfFileView`类,来以`django-sendfile`方式进行图片的提供。此视图可开箱即用: 117 | 118 | ```python 119 | from wagtail.images.views.serve import SendFileView 120 | 121 | urlpatterns = [ 122 | ... 123 | 124 | url(r'^images/([^/]*)/(\d*)/([^/]*)/[^/]*$', SendFileView.as_view(), name='wagtailimages_serve'), 125 | ] 126 | ``` 127 | 128 | 可对其加以定制,以对`SENDFILE_BACKEND`中定义的后端进行覆写: 129 | 130 | ```python 131 | from wagtail.images.views.serve import SendFileView 132 | from project.sendfile_backends import MyCustomBackend 133 | 134 | class MySendFileView(SendFileView): 135 | backend = MyCustomBackend 136 | ``` 137 | 138 | 还可将其定制为发送私有文件。比如在要求仅为要求认证(例如对于Django >= 1.9): 139 | 140 | ```python 141 | from django.contrib.auth.mixins import LoginRequiredMixin 142 | from wagtail.images.views.serve import SendFileView 143 | 144 | class PrivateSendFileView(LoginRequiredMixin, SendFileView): 145 | raise_exception = True 146 | ``` 147 | -------------------------------------------------------------------------------- /advanced_topics/i18n/duplicate_tree.md: -------------------------------------------------------------------------------- 1 | # 创建多语言站点(通过复制页面树的方式) 2 | 3 | 此教程将给出一种Wagtail中通过复制页面树的方式,创建多语言站点的方法。 4 | 5 | 比如: 6 | 7 | ```sh 8 | / 9 | en/ 10 | about/ 11 | contact/ 12 | fr/ 13 | about/ 14 | contact/ 15 | ``` 16 | 17 | 18 | ## 根页面 19 | 20 | 根页面(`/`)需要去侦测浏览器语言并将不同语言的浏览器请求,转发到正确语言的主页(`/en/`、`/fr/`)。根页面应位处站点根部(那里也是主页通常的所在)。 21 | 22 | 这里就必须设置 Django 的`LANGUAGES` 设置项,从而不会将那些非英语或法语的用户,重定向到不存在的页面。 23 | 24 | ```python 25 | # settings.py 26 | 27 | LANGUAGES = ( 28 | ('en', _("English")), 29 | ('fr', _("French")), 30 | ) 31 | ``` 32 | 33 | ```python 34 | # models.py 35 | 36 | from django.utils import translation 37 | from django.http import HttpResponseRedirect 38 | 39 | from wagtail.core.models import Page 40 | 41 | class LanguageRedirectionPage(Page): 42 | 43 | def serve(self, request): 44 | # 此方法仅会返回一个在 Django 的 LANGUAGE 设置项中的某个语言 45 | language = translation.get_language_from_request(request) 46 | 47 | return HttpResponseRedirect(self.url + language + '/') 48 | ``` 49 | 50 | 51 | ## 将全部页面链接起来 52 | 53 | 将同一页面的不同语言版本链接在一起,从而允许访问者可以轻松地在语言之间进行切换,将是有用的。但又不打算过多地增加站点编辑的负担,理想情况下,站点编辑只需将这些相同页面的一个版本,与其他版本链接起来,那么其他版本之间的链接将隐式地创建出来。 54 | 55 | 因为此做法需要添加到所有翻译的页面类型,所以最好将此做法放到混入中(a mixin)。 56 | 57 | 下面是一个如何实现此做法的示例(英语作为主语言,法语/西班牙语作为替代语言): 58 | 59 | ```python 60 | from wagtail.core.models import Page 61 | from wagtail.admin.edit_handlers import MultiFieldPanel, PageChooserPanel 62 | 63 | class TranslatablePageMixin(models.Model): 64 | # 每种替代语言对应一个链接 65 | # 这些属性与方法,应只应用在主语言的页面上(也就是英语) 66 | 67 | french_link = models.ForeignKey(Page, null=True, on_delete=models.SET_NULL, blank=True, related_name='+') 68 | spanish_link = models.ForeignKey(Page, null=True, on_delete=models.SET_NULL, blank=True, related_name='+') 69 | 70 | panels = [ 71 | PageChooserPanel('french_link'), 72 | PageChooserPanel('spanish_link'), 73 | ] 74 | 75 | def get_language(self): 76 | """ 77 | 此方法返回的时该页面的语言代码。 78 | """ 79 | 80 | # 通过对本页面的祖先进行查找,以找到他的语言代码 81 | # 语言主页位于深度 3 处(The language homepage is located at depth 3) 82 | 83 | language_homepage = self.get_ancestors(inclusive=True).get(depth=3) 84 | 85 | # 语言主页的别名,应总是被设置为语言代码 86 | return language_homepage.slug 87 | 88 | # 用于找出本页面主语言的方法 89 | # 这是通过对上面的链接进行反向追溯完成的(this works by reversing the above links) 90 | 91 | def english_page(self): 92 | """ 93 | 该方法找出本页面的英语版本 94 | """ 95 | language = self.get_language() 96 | 97 | if language == 'en': 98 | return self 99 | elif language == 'fr': 100 | return type(self).objects.filter(french_link=self).first().specific 101 | elif language == 'es': 102 | return type(self).objects.filter(spanish_link=self).first().specific 103 | 104 | 105 | # 这里需要某种找出本页面的每种替代语言的一个版本的方法。 106 | # 这些方法工作原理一样。他们首先找出页面的主要语言版本(也就是英语)。 107 | # 然后从主要语言版本开始,就只需跟随链接,就能获得相应语言的正确版本了。 108 | 109 | def french_page(self): 110 | """ 111 | 此方法找出该页面的法语版本 112 | """ 113 | 114 | english_page = self.english_page() 115 | 116 | if english_page and english_page.french_link: 117 | return english_page.french_link.specific 118 | 119 | def spanish_page(self): 120 | """ 121 | 此方法找出该页面的西班牙版本 122 | """ 123 | 124 | english_page = self.english_page() 125 | 126 | if english_page and english_page.spanish_link: 127 | return english_page.spanish_link.specific 128 | 129 | class Meta: 130 | abstract = True 131 | 132 | class AboutPage(Page, TranlatablePageMixin): 133 | ... 134 | 135 | content_panels = [ 136 | ... 137 | 138 | MutliFieldPanel(TranslatablePageMixin.panels, '语言链接') 139 | ] 140 | 141 | class ContactPage(Page, TranslatablePageMixin): 142 | ... 143 | 144 | content_panels = [ 145 | ... 146 | 147 | MultiFieldPanel(TranslatablePageMixin.panels, '语言链接') 148 | ] 149 | ``` 150 | 151 | 随后在模板中就可以向下面这样,利用上这些方法了: 152 | 153 | {% raw %} 154 | 155 | {% if page.english_page and page.get_language != 'en' %} 156 | {% trans "View in English" %} 157 | {% endif %} 158 | 159 | {% if page.french_page and page.get_language != 'fr' %} 160 | {% trans "View in English" %} 161 | {% endif %} 162 | 163 | {% if page.spanish_page and page.get_language != 'es' %} 164 | {% trans "View in English" %} 165 | {% endif %} 166 | {% endraw %} 167 | -------------------------------------------------------------------------------- /topics/search/backends.md: -------------------------------------------------------------------------------- 1 | # 关于搜索后端 2 | 3 | 4 | Wagtail有着对多种后端的支持,从而提供了使用数据库的搜索,或使用诸如Elasticsearch这样的外部服务进行搜索的选择。默认启用的是数据库后端。 5 | 6 | 可使用`WAGTAILSEARCH_BACKENDS`设置,来配置要使用的后端: 7 | 8 | ```python 9 | WAGTAILSEARCH_BACKENDS = { 10 | 'default': { 11 | 'BACKEND': 'wagtail.search.backends.db', 12 | } 13 | } 14 | ``` 15 | 16 | 17 | ## `AUTO_UPDATE` 18 | 19 | 默认Wagtail将自动保持所有索引处于更新状态。此默认行为在编辑内容时,将对性能造成影响,尤其是在索引驻留在外部服务上时。 20 | 21 | `AUTO_UPDATE`设置,允许在单个索引基础上,关闭默认行为: 22 | 23 | ```python 24 | WAGTAILSEARCH_BACKENDS = { 25 | 'default': { 26 | 'BACKEND': ..., 27 | 'AUTO_UPDATE': False, 28 | } 29 | } 30 | ``` 31 | 32 | 如关闭了自动更新,那么就必须定期运行`update_index`命令,以保持索引与数据库同步。 33 | 34 | ## `ATOMIC_REBUILD` 35 | 36 | > **警告** 此选项在Elasticsearch 5.4及更高版本上不会工作,是因为[别名处理中的一个bug](https://github.com/elastic/elasticsearch/issues/24644) 影响到这些版本。 37 | 38 | 默认(使用Elasticsearch后端时)在`update_index`运行时,Wagtail会删除索引并从头开始重建出来。这就会导致在重建完成之前搜索引擎不会返回结果,同时这也有着发生了错误时无法回滚的风险。 39 | 40 | 将`ATOMIC_REBUILD`设置项目,设置为`True`,就会令到Wagtail重建为一个独立的索引,而在新的索引完全建立之前,保持原有的索引处于活动状态。在重建完成之后,新旧索引进行原子交换,且旧的索引被删除。 41 | 42 | ## `BACKEND` 43 | 44 | 下面是Wagtail原生支持的后端清单。 45 | 46 | ### 数据库后端(默认支持 47 | 48 | `wagtail.search.backends.db` 49 | 50 | 数据库后端是甚为基础的,而仅是打算供开发与小型站点所用。其无法依相关度对结果进行排序,从而严重妨碍了其在对大量页面集进行搜索时的可用性。 51 | 52 | 数据库后端不具备对以下特性的支持: 53 | 54 | + 在`Page`基类的子类中字段的搜索(除非该类是直接进行搜索的) 55 | + [对可调用属性与其他属性的索引](#indexing-callable-fields) 56 | + 将重音字符转换成ASCII字符(注:accendted characters) 57 | 58 | 在上述任何一个特性都是重要的情况下,就要使用Elasticsearch了。 59 | 60 | ### PostgreSQL 的后端 61 | 62 | `wagtail.contrib.postgres_search.backend` 63 | 64 | 在使用PostgreSQL作为数据库,且站点页面数少于一百万时,就可能打算使用此后端了。 65 | 66 | 请参阅[PostgreSQL的搜索引擎](reference/contrib.html#postgres-search)以了解更多知识。 67 | 68 | 69 | ### Elasticsearch 后端 70 | 71 | *Wagtail 2.1 的改动: 加入了对 Elasticsearch 6.x 的支持* 72 | 73 | Wagtail支持 Elasticsearch 的版本2、5与6。请使用对应版本的后端: 74 | 75 | `wagtail.search.backends.elasticsearch2` (Elasticsearch 2.x) 76 | 77 | `wagtail.search.backends.elasticsearch5` (Elasticsearch 5.x) 78 | 79 | `wagtail.search.backends.elasticsearch6` (Elasticsearch 6.x) 80 | 81 | 使用此后端的前提,是先要有[Elasticsearch](https://www.elastic.co/downloads/elasticsearch)服务本身,以及通过`pip`安装上[elasticsearch-py](http://elasticsearch-py.readthedocs.org/)这个包。该包的大版本号要与所安装的Elasticsearch的版本匹配: 82 | 83 | ```sh 84 | $ pip install "elasticsearch>=2.0.0,<3.0.0" # 对于Elasticsearch 2.x 85 | 86 | $ pip install "elasticsearch>=5.0.0,<6.0.0" # 对于Elasticsearch 5.x 87 | 88 | $ pip install "elasticsearch>=6.0.0,<6.3.1" # 对于Elasticsearch 6.x 89 | ``` 90 | 91 | > **注意** 版本 `6.3.1` 的 Elasticsearch客户端库与Wagtail不兼容。请使用 `6.3.0`或更早版本。 92 | 93 | 94 | 后端实在设置中配置的: 95 | 96 | ```python 97 | WAGTAILSEARCH_BACKENDS = { 98 | 'default': { 99 | 'BACKEND': 'wagtail.search.backends.elasticsearch2', 100 | 'URLS': ['http://localhost:9200'], 101 | 'INDEX': 'wagtail', 102 | 'TIMEOUT': 5, 103 | 'OPTIONS': {}, 104 | 'INDEX_SETTINGS': {}, 105 | } 106 | } 107 | ``` 108 | 109 | 与`BACKEND`不同,其他键是可选的,且默认为上面的那些值。在`OPTIONS`中定义的所有键,都被直接作为区分大小写的关键字参数(比如`'max_retries': 1`),传递给 Elasticsearch的构造器。 110 | 111 | `INDEX_SETTINGS`则是一个用于对默认创建索引方式设置进行覆写的字典。该创建索引方式设置项,定义在模块`wagtail/wagtail/wagtailsearch/backends/elasticsearch.py`模块里`ElasticsearchSearchBacken`类的内容。将加入所有的新键,对于既有键,如其不是一个字典,那么都将以新的值进行替换。下面是一个如何配置分片数,以及将意大利语的语言分析器作为默认分析器的示例: 112 | 113 | ```python 114 | WAGTAILSEARCH_BACKENDS = { 115 | 'default': { 116 | ..., 117 | 'INDEX_SETTINGS': { 118 | 'settings': { 119 | 'index': { 120 | 'number_of_shards': 1, 121 | }, 122 | 'analysis': { 123 | 'analyzer': { 124 | 'default': { 125 | 'type': 'italian' 126 | } 127 | } 128 | } 129 | } 130 | } 131 | } 132 | } 133 | ``` 134 | 135 | 若不在开发或生产环境选择运行一个Elasticsearch服务器,那么有着多个可用的第三方主机服务,包括[Bonsai](https://bonsai.io/signup),该站点提供了一个适合与测试与开发的免费帐号。要使用Bonsai: 136 | 137 | + 在Bonsai注册一个帐号 138 | + 使用Bonsai的仪表盘创建一个集群 139 | + 使用Bonsai仪表盘中的该集群URL,配置`WAGTAILSEARCH_BACKENDS`中的`URLS`条目 140 | + 运行`./manage.py update_index`命令 141 | 142 | 143 | ### Amazon AWS 的Elasticsearch 144 | 145 | Wagtail的Elasticsearch后端,是与[Amazon 的Elasticsearch服务](https://aws.amazon.com/elasticsearch-service/)兼容的,但需要额外配置,以处理基于IMA的认证。这可通过[requests-aws4auth](https://pypi.python.org/pypi/requests-aws4auth) `pip` 包,与以下的配置来完成: 146 | 147 | ```python 148 | from elasticsearch import RequestsHttpConnection 149 | from requests_aws4auth import AWS4AUTH 150 | 151 | WAGTAILSEARCH_BACKENDS = { 152 | 'default': { 153 | 'BACKEND': 'wagtail.search.backends.elasticsearch2', 154 | 'INDEX': 'wagtail', 155 | 'TIMEOUT': 5, 156 | 'HOSTS': [{ 157 | 'host': 'YOURCLUSTER.REGION.es.amazonaws.com', 158 | 'port': 443, 159 | 'use_ssl': True, 160 | 'verify_certs': True, 161 | 'http_auth': AWS4AUTH('ACCESS_KEY', 'SECRET_KEY', 'REGION', 'es'), 162 | }], 163 | 'OPTIONS': { 164 | 'connection_class': RequestsHttpConnection, 165 | } 166 | } 167 | } 168 | ``` 169 | 170 | ### 构造自己的后端 171 | 172 | **Rolling Your Own** 173 | 174 | Wagtail搜索后端实现了在`wagtail/wagtail/wagtailsearch/backends/base.py`中的接口。在最低限度下,后端的`search()`方法必须返回一个对象集合或`model.objects.none()`。而对于一个具有完整特性的搜索后端,请在`elasticsearch.py`中查看Elasticsearch的后端代码。 175 | -------------------------------------------------------------------------------- /advanced_topics/customisation/admin_templates.md: -------------------------------------------------------------------------------- 1 | # 对管理模板进行定制 2 | 3 | 在Wagtail项目中,可能希望在管理界面中,使用自己的品牌元素,来替换默认的Wagtail徽标等元素。可经由Django的继承机制,实现此目标。 4 | 5 | 需要在某个应用目录下,创建一个`templates/wagtailadmin/`的文件夹 -- 这既可以是一个既有的文件夹,也可以是为此目的而新建的文件夹,比如 `dashboard`。该应用必须是已在 `INSTALLED_APPS` 中,于`wagtail.admin`之前已注册的应用: 6 | 7 | ```python 8 | INSTALLED_APPS = ( 9 | # ... 10 | 'dashboard', 11 | 12 | 'wagtail.core', 13 | 'wagtail.admin', 14 | 15 | # ... 16 | ) 17 | ``` 18 | 19 | 20 | ## 品牌的定制 21 | 22 | 可用于对管理界面中的品牌加以定制的模板块包含以下这些: 23 | 24 | + `branding_logo` 25 | 26 | 要替换默认的徽标,就要创建一个对默认的`branding_logo`块进行覆写的模板文件 `dashboard/templates/wagtailadmin/base.html`: 27 | 28 | {% raw %} 29 | 30 | {% extends "wagtailadmin/base.html" %} 31 | {% load static %} 32 | 33 | {% block branding_logo %} 34 |一些额外的表单内容
174 | {{ block.super }} 175 | {% endblock %} 176 | {% endraw %} 177 | 178 | ## 对客户端组件进行扩展 179 | 180 | 一些Wagtail的管理界面,是作为带有 [React](https://reactjs.org/) 的客户端JavaScript代码编写而成的。为了对这些组件进行定制或扩展,就需要用到 React,以及其他一些相关的库。为令到此工作更为容易,Wagtail将其自己与React有关的依赖,作为管理界面中的全局依赖而加以了暴露。下面时这些可用的包: 181 | 182 | ```javascript 183 | // 'focus-trap-react' 184 | window.FocusTrapReact; 185 | // 'react' 186 | window.React; 187 | // `react-dom` 188 | window.ReactDOM; 189 | // 'react-transition-group/CSSTransitionGroup' 190 | window.CSSTransitionGroup; 191 | ``` 192 | 193 | Wagtail还暴露了其自己的一些 React 组件。可重用这些组件: 194 | 195 | ```javascript 196 | window.wagtail.components.Icon; 197 | window.wagtail.components.Portal; 198 | ``` 199 | 200 | 包含了富文本编辑器的页面还可以访问到下面这些组件: 201 | 202 | ```javascript 203 | // `draft.js` 204 | window.DraftJS; 205 | // 'draftail' 206 | window.Draftail; 207 | 208 | // Wagtail 与 Draftail有关的 AIPs 及组件。 209 | window.draftail; 210 | window.draftail.ModalWorkflowSource; 211 | window.draftail.Tooltip; 212 | window.draftail.TooltipEntity; 213 | ``` 214 | -------------------------------------------------------------------------------- /topics/search/indexing.md: -------------------------------------------------------------------------------- 1 | 2 | # 索引的建立 3 | 4 | 要令到模型可视化,就需要将其加入到搜索索引中。所有页面、图片与文档都被索引起来,那么就可以立即开始对他们进行搜索了。 5 | 6 | 在某个页面或图片基类的子类中建立了额外字段时,可能会将这些新的字段,也加入到搜索索引中,从而令到用户的搜索查询,对这些子类的内容进行匹配。请参阅[对额外字段建立索引](#indexing-extra-fields)。 7 | 8 | 在希望将定制模型纳入搜索时,请参阅[建立定制模型的索引](#indexing-custom-models)。 9 | 10 | ## 更新索引 11 | 12 | 在搜索索引与数据库分离的情况下(比如使用Elesticsearch时),就要让二者保持同步状态。有两种方式可以完成此操作:使用搜索信号处理器,或周期性地调用`update_index`命令。处于最佳速度与可靠性的考虑,最好的做法是在可能的情况下二者同时使用。 13 | 14 | ## 关于信号处理器 15 | 16 | `wagtailsearch`库提供了一些绑定到所有已索引模型的保存/删除信号的信号处理器。这将自动在已于`WAGTAILSEARCH_BACKENDS`中注册的所有后端中,添加及删除相应他们。在`wagtail.search`应用装入时,这些信号处理器自动进行了注册。 17 | 18 | **关于`update_index`命令** 19 | 20 | Wagtail还提供了用于从头开始重建索引的一个命令 21 | 22 | ```bash 23 | ./manage.py update_index 24 | ``` 25 | 26 | 推荐每周运行一次此命令,以及在以下时刻运行他: 27 | 28 | + 在经由脚本(比如导入内容后)创建了页面后 29 | + 在对模型或搜索的配置进行了修改之后 30 | 31 | 因为此命令运行时的搜索不会返回结果,因此要避免在峰值时段运行此命令。 32 | 33 | 34 | ## 对额外字段进行索引 35 | 36 | > **警告** 数据库后端并不支持对额外字段的索引。在使用数据库后端是,经由`search_fields`所定义的所有其他字段,都会被忽略。 37 | 38 | 39 | 必要要将字段显式地加入到那些由`Page`基类所派生的模型的`search_fields`字段,以便对这些字段进行搜索/过滤。这是通过对`search_fields`进行覆写,来将一个额外的`SearchField`/`FilterField`字段给他,而完成的。 40 | 41 | __示例__ 42 | 43 | 下面的代码创建了有着两个字段的`EventPage`模型:`description`与`date`。`description`作为了`SearchField`进行索引,而`date`则作为`FilterField`进行索引。 44 | 45 | ```python 46 | from watail.search import index 47 | from django.utils import timezone 48 | 49 | class EventPage(Page): 50 | description = models.TextField() 51 | date = models.DateField() 52 | 53 | search_fields = Page.search_fields + [ # 这里从 Page 基类继承 search_fields 54 | index.SearchField('description'), 55 | index.FilterField('date'), 56 | ] 57 | 58 | # 获取在标题或活动描述中包含 “Christmas” 字符串的未来活动 59 | >>> EventPage.objects.filter(date__gt=timezone.now()).search("Christmas") 60 | ``` 61 | 62 | ## 关于`index.SearchField` 63 | 64 | 指定用于在模型上执行全文搜索的字段,通常是指文本字段。 65 | 66 | **选项** 67 | 68 | + `partial_match(boolean)` -- 将该选项设置为真时,允许结果在部分词上匹配。比如此选项默认对标题就设置为真,那么在某个页面的标题为`Hello World!`时,若用户在搜索框中输入的是`Hel`,则该页面将会被找到。 69 | 70 | + `boost(int/float)` -- 此选项允许将一些字段设置为较其他字段更为重要。将某字段的此选项设置为一个较高的数字,将那些在该字段匹配的页面,在结果共排序靠前。通常页面标题字段的该选项被设置为`2`,所有其他字段的该选项被设置为`1`。 71 | 72 | + `es_extra(dict)` -- 指定该字段允许开发者设置或覆写Elasticsearch映射中该字段上的所有设置。在打算使用某些Wagtail尚不支持的Elasticsearch的特性时,就要用到此选项。 73 | 74 | 75 | ## 关于`index.FilterField` 76 | 77 | 指定要加入到搜索索引的字段,但这些字段不用于全文搜索。而是可以在搜索结果上运行过滤器。 78 | 79 | 80 | ## 关于`index.RelatedFields` 81 | 82 | 此特性允许对相关对象的字段进行索引。其工作于相关字段的所有类型,包含他们的反向访问器(This allows you to index fields from related objects. It works on all types of related fields, including their reverse accessors)。 83 | 84 | 比如这里有一个到书籍作者的`ForeignKey`,就可以将作者模型的`name`与`date_of_birth`字段,嵌入到书籍模型内: 85 | 86 | ```python 87 | from wagtail.search import index 88 | 89 | class Book(models.Model, index.Indexed): 90 | ... 91 | 92 | search_fields = [ 93 | index.SearchField('title'), 94 | index.FilterField('published_date'), 95 | 96 | index.RelatedFields('author', [ 97 | index.SearchField('name'), 98 | index.FilterField('date_of_birth'), 99 | ]), 100 | ] 101 | ``` 102 | 103 | __`index.RelatedFields`上的过滤__ 104 | 105 | 使用`QuerySet`编程接口在`index.RelatedFields`中的所有`index.FilterFields`上进行过滤,都是不可能的。不过这些字段既然有被索引起来,那么就有可能通过手动查询Elasticsearch来用到他们。 106 | 107 | Wagtail计划在未来的发行中,实现经由`QuerySet`在`index.RelatedFields`上的过滤。 108 | 109 | 110 | 111 | ## 对可调用及其他属性的索引 112 | 113 | **Indexing callables and other attributes** 114 | 115 | > **注意** [数据库后端(默认)](#backends-database) 不支持此特性。 116 | 117 | 搜索/过滤器字段无需是Django模型字段。他们还可以是模型类的方法或属性。 118 | 119 | 此特性的一种用处,是对那些Django自动创建的、带有选项的字段的`get_*_display`方法的索引。 120 | 121 | ```python 122 | from wagtail.search import index 123 | 124 | class EventPage(Page): 125 | 126 | IS_PRIVATE_CHOICES = ( 127 | (False, "公开的"), 128 | (False, "私有的"), 129 | ) 130 | 131 | is_private = models.BooleanField(choices=IS_PRIVATE_CHOICES) 132 | 133 | search_fields = Page.search_fields + [ 134 | # 对人类可读的字符串进行索引,以进行搜索 135 | index.SearchField('get_is_private_display'), 136 | 137 | # 对逻辑值进行索引,以进行过滤 138 | index.FilterField('is_private'), 139 | ] 140 | ``` 141 | 142 | 可调用属性还提供到一种对相关模型字段的索引方法(Callables also provide a way to index fields from related models)。在[内联面板与模型集群](reference/pages.html#panels-inline-panels)的示例中,就是通过相关链接的标题,来对各个`BookPage`进行索引的。 143 | 144 | ```python 145 | class BookPage(Page): 146 | 147 | # ... 148 | 149 | def get_related_link_titles(self): 150 | 151 | # 获取到标题清单,并将他们级联起来 152 | return '\n'.join(self.related_links.all().values_list('name', flat=True)) 153 | 154 | search_fields = Page.search_fields + [ 155 | # ... 156 | index.SearchField('get_realted_link_titles'), 157 | ] 158 | ``` 159 | 160 | 161 | ## 对定制模型进行索引 162 | 163 | 所有Django模型,都可以被索引与搜索。 164 | 165 | 要实现这一点,就要从`index.Indexed`进行继承,并将一些`search_fields`加入到该模型。 166 | 167 | ```python 168 | from wagtail.search import index 169 | 170 | class Book(index.Indexed, models.Model): 171 | title = models.CharField(max_length=255) 172 | genre = models.CharField(max_length=255, choices=GENRE_CHOICES) 173 | author = models.ForeignKey(Author, on_delete=models.CASCADE) 174 | published_date = models.DateTimeField() 175 | 176 | search_fields = [ 177 | index.SearchField('title', partial_match=True, boost=10), 178 | index.SearchField('get_genre_display'), 179 | 180 | index.FilterField('genre'), 181 | index.FilterField('author'), 182 | index.FilterField('published_date'), 183 | ] 184 | 185 | # 因为此模型在其QuerySet中并没有一个搜索方法,因此就必须直接在后端调用搜索 186 | >>> from wagtail.search.backends import get_search_backend 187 | >>> s = get_search_backend() 188 | 189 | # 运行一次对 Roald Dohl 所写的书的搜索 190 | >>> roald_dahl = Author.objects.get(name="Roald Dahl") 191 | >>> s.search("chocolate factory", Book.objects.filter(author=roald_dahl)) 192 | [66 | {{ advert.text }} 67 |
68 | {% endfor %} 69 | ``` 70 | 71 | 随后在页面模板中,据可以这样来将该片段模板标签包含进来了: 72 | 73 | {% raw %} 74 | {% load wagtailcore_tags demo_tags %} 75 | 76 | ... 77 | {% block content %} 78 | ... 79 | 80 | {% adverts %} 81 | {% endblock %} 82 | {% endraw %} 83 | 84 | ## 将页面绑定到片段 85 | 86 | 在上述示例中,`adverts`的清单是一个固定清单,其显示是独立于页面内容的。这种形式对于某个侧边栏中的普通面板可能是预期的效果,但在其他场景下,可能希望对某个页面内容中的特定片段进行引用(this might be what you want for a common panel in a sidebar, say -- but in other scenarios you may wish to refer to a particular snippet from within a page's content)。这可通过在页面模型中定义一个到片段模型的外键,并将一个`SnippetChooserPanel`到添加到页面的`content_panels`来实现。比如在打算指定某个`advert`要出现在`BookPage`上时: 87 | 88 | ```python 89 | from wagtail.snippets.edit_handlers import SnippetChooserPanel 90 | 91 | # ... 92 | 93 | class BookPage(Page): 94 | 95 | advert = models.ForeignKey( 96 | 'demo.Advert', 97 | null=True, 98 | blank=True, 99 | on_delete=models.SET_NULL, 100 | related_name='+' 101 | ) 102 | 103 | content_panels = Page.content_panels + [ 104 | SnippetChooserPanel('advert'), 105 | # ... 106 | ] 107 | ``` 108 | 109 | 随后该片段就可以在模板中作为`page.advert`进行访问了。 110 | 111 | 要将多个`adverts`附加到某个页面,就可将`SnippetChooserPanel`放置在`BookPage`的某个内联子对象上,而不要在`BookPage`上。下面的子模型被命名为了`BookPageAdvertPlacement`(之所以这样命名,是因为对于每次将`advert`放置在`BookPage`上时,都有一个这样的对象,here this child model is named `BookPageAdvertPlacement`(so called because there is on such object for each time that an advert is placed on a BookPage))。 112 | 113 | ```python 114 | from django.db import models 115 | 116 | from wagtail.core.models import Page, Orderable 117 | from wagtail.snippets.edit_handlers import SnippetChooserPanel 118 | 119 | from modelcluster.fields import ParentalKey 120 | 121 | ... 122 | 123 | class BookPageAdvertPlacement(Orderable, models.Model): 124 | 125 | page = ParentalKey('demo.BookPage', on_delete=models.CASCADE, related_name='advert_placements') 126 | advert = models.ForeignKey('demo.Advert', on_delete=models.CASCADE, related_name='+') 127 | 128 | class Meta: 129 | verbose_name = "广告位" 130 | verbose_name_plural = "广告位" 131 | 132 | panels = [ 133 | SnippetChooserPanel('advert'), 134 | ] 135 | 136 | def __str__(self): 137 | return self.page.title + " -> " + self.advert.text 138 | 139 | class BookPage(Page): 140 | ... 141 | 142 | content_panels = Page.content_panels + [ 143 | InlinePanel('advert_placements', label="广告"), 144 | # ... 145 | ] 146 | ``` 147 | 148 | 现在这些子对象就可经由页面的`advert_placements`属性访问到了,且从那里可以`advert`访问到链接的`Advert`。在`BookPage`的模板中,可包含以下代码: 149 | 150 | ```html 151 | {% for advert_placement in page.advert_placements.all %} 152 |{{ advert_placement.advert.text }}
153 | {% endfor %} 154 | ``` 155 | 156 | ## 令到片段可被搜索 157 | 158 | 在片段模型继承了[对定制模型进行索引](search.html#indexing-custom-models)所降到的`wagtail.search.index.Indexed`时,Wagtail将自动把一个搜索框添加到那个片段类型的选择器界面上。比如该`Advert`片段可像下面这样做成可搜索的: 159 | 160 | ```python 161 | ... 162 | 163 | from wagtail.search import index 164 | ... 165 | 166 | @register_snippet 167 | class Advert(index.Indexed, models.Model): 168 | url = models.URLField(null=True, blank=True) 169 | text = models.CharField(max_length=255) 170 | 171 | panels = [ 172 | FieldPanel('url'), 173 | FieldPanel('text'), 174 | ] 175 | 176 | search_fields = [ 177 | index.SearchField('text', partial_match=True), 178 | ] 179 | ``` 180 | 181 | ## 给片段打上标签 182 | 183 | 将标签添加到片段,与将标签添加到页面非常类似。唯一差别在于应在`ClusterTaggableManager`处使用`taggit.manager.TaggableManager`。 184 | 185 | ```python 186 | from modelcluster.fields import ParentalKey 187 | from modelcluster.models import ClusterableModel 188 | from taggit.models import TaggedItemBase 189 | from taggit.managers import TaggableManager 190 | 191 | class AvertTag(TaggedItemBase): 192 | content_object = ParentalKey('demo.Advert', on_delete=models.CASCADE, related_name='taggged_items') 193 | 194 | @register_snippet 195 | class Advert(ClusterableModel): 196 | 197 | ... 198 | tags = TaggableManager(through=AdvertTag, blank=True) 199 | 200 | panels = [ 201 | ... 202 | FieldPanel('tags'), 203 | ] 204 | ``` 205 | 206 | 关于更多有关在视图中使用标签的知识,请参阅[给页面打标签的文档](reference/pages.html#tagging)。 207 | -------------------------------------------------------------------------------- /advanced_topics/customisation/page_editing_interface.md: -------------------------------------------------------------------------------- 1 | # 编辑界面的定制 2 | 3 | ## 分页界面的定制 4 | 5 | 标准情况下,Wagtail将页面的面板,组织为三个分页:“内容”、“Promote”与“设置”。对于内容片段,Wagtail则是将所有面板放到一个分页中。依据站点的需求,可能希望对特定页面或内容片段下的此种默认做法进行定制 -- 比如为侧边栏内容而添加一个额外的分页。这可通过在页面或内容片段模型上指定一个`edit_handler`属性来实现。比如: 6 | 7 | ```python 8 | from wagtail.admin.edit_handler import TabbedInterface, ObjectList 9 | 10 | class BlogPage(Page): 11 | # 此处省略了字段定义部分 12 | 13 | content_panels = [ 14 | FieldPanel('title', classname="full title"), 15 | FieldPanel('data'), 16 | FieldPanel('body', classname="full"), 17 | ] 18 | 19 | sidebar_content_panels = [ 20 | SnippetChooserPanel('advert'), 21 | InlinePanel('related_links', label="相关链接") 22 | ] 23 | 24 | edit_handler = TabbedInterface([ 25 | ObjectList(content_panels, heading="内容"), 26 | ObjectList(sidebar_content_panels, heading="侧边栏内容"), 27 | ObjectList(Page.promote_panels, heading="Promote"), 28 | ObjectList(Page.settings_panels, heading="设置项", classname="settings"), 29 | ]) 30 | ``` 31 | 32 | 33 | ## 关于富文本(HTML) 34 | 35 | Wagtail提供了一个通用目的、用于创建富文本内容(HTML)及将诸如图片、视频与文档等媒体文件加以嵌入的所见即所得编辑器。在定义某个模型字段时,使用`RichTextField`函数,就可以将该编辑器包含到模型中: 36 | 37 | ```python 38 | from wagtail.core.fields import RichTextField 39 | from wagtail.admin.edit_handlers import FieldPanel 40 | 41 | class BookPage(Page): 42 | book_text = RichTextField() 43 | 44 | content_panels = Page.content_panels + [ 45 | FieldPanel('body', classname="full"), 46 | ] 47 | ``` 48 | 49 | `RichTextField`继承了Django的基本`TextField`字段,因此可像使用普通Django字段那样,将任意字段参数传入到`RichTextField`。该字段并不需要特别的面板,同时可使用`FieldPanel`进行定义。 50 | 51 | 但`RichTextField`的模板输出较为特殊,而需要加以过滤以保留所嵌入的内容。关于这个问题,请参阅[富文本(过滤器)](https://wagtail.xfoss.com/topics/writing_templates.html#rich-text-filter)。 52 | 53 | ### 对富文本字段中的特性加以限制 54 | 55 | 默认该富文本编辑器提供给用户相当多的文本格式化与插入诸如图片等嵌入式内容的选项。然而可能希望将某个富文本字段限制到更为受限的特性集合 -- 比如: 56 | 57 | + 该字段可能打算作为短文本的内容片段,比如将在索引页面上拉出来的一个概要,那样的话嵌入图片或视频就不适当了; 58 | 59 | + 在页面内容是通过使用 [`StreamField`](https://wagtail.xfoss.com/topics/streamfield.html#streamfield)进行定义的时,诸如标题、图片及视频等元素,就通常赋予了其自身的块类型,同时为普通段落文本使用某种富文本的块类型;在此情况下,再允许标题及图片存在于富文本内容,就会显得累赘(并导致设计上无法保持一致)。 60 | 61 | 可通过将带有希望使用的特性标识符的清单的一个`features`关键字参数,传递给`RichTextField`函数,来完成富文本字段特性的限制: 62 | 63 | ```python 64 | body = RichTextField(features=['h2', 'h3', 'bold', 'italic', 'link']) 65 | ``` 66 | 67 | 默认Wagtail安装所提供了以下这些特性标识符: 68 | 69 | + `h1`、`h2`、`h3`、`h4`、`h5`、`h6` -- 标题元素 70 | + `bold`、`italic` -- 粗体/斜体文本 71 | + `ol`、`ul` -- 有序/无序列表 72 | + `hr` -- 水平线 73 | + `link` -- 页面、外部网页与电子邮件链接 74 | + `document-link` -- 到文档的链接 75 | + `image` -- 嵌入图片 76 | + `embed` -- 嵌入媒体(请参阅 [嵌入式内容](https://wagtail.xfoss.com/advanced_topics/embeds.html#embedded-content)) 77 | 78 | 还有几个额外的特性标识符。他们默认没有开启,但可在标识符清单中使用他们。这些额外标识符如下所示: 79 | 80 | + `code` -- 内联代码 81 | + `superscript`、`subscript`、`strikethrough` -- 文本格式化 82 | + `blockquote` -- 引用块(blockquote) 83 | 84 | 以下页面对创建新特性的流程,进行了讲解: 85 | 86 | + [富文本的内部元素](rich_text_internals.md) 87 | + [对Draftail编辑器进行扩展](extending_draftail.md) 88 | + [对Hallo编辑器进行扩展](extending_hallo.md) 89 | 90 | ### 富文本编辑器中的图片格式问题 91 | 92 | 在Wagtail加载时,他将搜寻任何带有`image_formats.py`文件的应用,并执行其中的代码。这就提供了一种在`RichTextField`中插入图片时,对暴露给编辑器的格式选项进行定制的途径。 93 | 94 | 比如加入一个“缩略图”的格式: 95 | 96 | ```python 97 | # image_formats.py 98 | 99 | from wagtail.images.formats import Format, register_image_format 100 | 101 | register_image_format(Format('thumbnail', 'Thumbnail', 'richtext-image thumbnail', 'max-120x120')) 102 | ``` 103 | 104 | 这里是以`Format`类、`register_image_format`函数,以及可选的`unregister_image_format`函数的导入开始的。要注册一个新的`Format`,就要以`Format`对象作为参数,调用`register_image_format`。类`Format`则要取以下的构造器参数: 105 | 106 | + `name` 107 | 108 | 用于标识该格式的唯一性键。在解除此格式的注册时,就要以这个字符串,作为唯一的参数来调用`unregister_image_format`。 109 | 110 | + `label` 111 | 112 | 将图片插入到`RichTextField`中时,在选择器表单中使用的标签。 113 | 114 | + `classnames` 115 | 116 | 指派给所生成的`Lorem ipsum dolor sit amet
'), 130 | })) 131 | ``` 132 | 133 | + `wagtail.tests.utils.form_data.streafield(items)` 134 | 135 | 取得一个元组的清单(`block_tyep`、`value`),并将其转换为 `StreamField`的表单数据。在某个 `nested_form_data()` 调用中使用该方法,将字段名称作为键。 136 | 137 | ```python 138 | nested_form_data({'content': streamfield([ 139 | ('text', 'Hello, world'), 140 | ])}) 141 | 142 | # 将返回: 143 | # { 144 | # 'content-count': '1', 145 | # 'content-0-type': 'text', 146 | # 'content-0-value': 'Hello, world', 147 | # 'content-0-order': '0', 148 | # 'content-0-deleted': '', 149 | # } 150 | ``` 151 | 152 | 153 | + `wagtail.tests.utils.form_data.inline_formset(items, initial=0, min=0, max=1000)` 154 | 155 | 取得一个 `InlineFormset` 的表单数据清单,并将其转换为有效的POST数据。在某个 `nested_form_data()` 调用中使用此方法,以表单集的关系名称作为键(with the formset relation name as the key)。 156 | 157 | ```python 158 | nested_form_data({'lines': inline_formset([ 159 | {'text': 'Hello'}, 160 | {'text': 'World'}, 161 | ])}) 162 | 163 | # 将返回: 164 | # { 165 | # 'lines-TOTAL_FORMS': '2', 166 | # 'lines-INITIAL_FORMS': '0', 167 | # 'lines-MIN_NUM_FORMS': '0', 168 | # 'lines-MAX_NUM_FORMS': '1000', 169 | # 'lines-0-text': 'Hello', 170 | # 'lines-0-ORDER': '0', 171 | # 'lines-0-DELETE': '', 172 | # 'lines-1-text': 'World', 173 | # 'lines-1-ORDER': '1', 174 | # 'lines-1-DELETE': '', 175 | # } 176 | ``` 177 | 178 | 179 | ## Fixtures 180 | 181 | ### 使用 `dumpdata` 182 | 183 | 通过创建出一些开发环境中的内容,并使用Django 的 [dumpdata](https://docs.djangoproject.com/en/2.0/ref/django-admin/#django-admin-dumpdata) 命令,是为测试目的而创建 一些 [fixtures](https://docs.djangoproject.com/en/stable/howto/initial-data/)的最佳方法。 184 | 185 | 请注意默认的 `dumpdata` 将以主键来表示 `content_type`;在添加/移除模型时,这可能会导致一致性问题,因为内容类型是独立于 fixtures 而单独生成的。为防止这个问题,就要使用 `--natural-foreign` 命令开关,此命令开关将使用 `["app", "model"]` 来表示内容类型。 186 | 187 | ### 手动修改 188 | 189 | 可手动修改复制的 fixtures,或设置完全手动地编写这些 fixtures。以下是一些需要留意的地方。 190 | 191 | __定制页面模型__ 192 | 193 | 在创建 fixtures 中的定制页面模型时,将需要同时添加一个 `wagtailcore.page` 的条目,以及一个定制页面模型的条目。 194 | 195 | 假设有着一个定义了`Homepage(Page)` 类的 `website` 模块。那么就可以在某个 fixture 中创建以下的一个主页: 196 | 197 | ```python 198 | [ 199 | { 200 | "model": "wagtailcore.page", 201 | "pk": 3, 202 | "fileds": { 203 | "title": "客户的主页", 204 | "content_type": ["website", "homepage"], 205 | "depth": 2 206 | } 207 | }, 208 | { 209 | "model": "website.homepage", 210 | "pk": 3, 211 | "fields": {} 212 | } 213 | ] 214 | ``` 215 | 216 | __Treebeard 字段__ 217 | 218 | 为了令到像是 `get_parent` 这类页面树的操作正确工作,因此填入 `path` / `numchild` / `depth` 字段是必要的。在某些不同寻常的情况下,若未给出值,`url_path`是另一个可导致错误的字段。 219 | 220 | [Treebeard 文档](http://django-treebeard.readthedocs.io/en/latest/mp_tree.html) 可帮助理解其工作原理。 221 | -------------------------------------------------------------------------------- /advanced_topics/embeds.md: -------------------------------------------------------------------------------- 1 | # 嵌入的内容 2 | 3 | Wagtail支持从到外部服务提供商,如Youtube或Twitter等上的内容的URLs,生成嵌入代码。默认Wagtail将直接从相关提供商站点,使用 [oEmbed协议](https://oembed.com/) 获取嵌入的代码。 4 | 5 | Wagtail有着一个内建的大多数常见服务商的清单,且该清单可通过 [一项设置](#customising-embed-providers) 进行修改。Wagtail还支持使用 [Embedly](#embedly) 与 [定制的嵌入发现器](#custom-embed-finders) 来获取嵌入代码。 6 | 7 | 8 | ## 在站点上嵌入代码 9 | 10 | 对于大多数内容提供商来说,Wagtail的内容嵌入模块应可以直接开箱即用。可使用下列的任意方式来调用此模块: 11 | 12 | ### 富文本方式 13 | 14 | Wagtail的默认富文本编辑器,有着一个允许将嵌入代码放置于富文本中的“媒体”图标。不必做任何设置来开启此特性;只要确保该富文本字段的内容,在魔板中是通过`|richtext`过滤器进行传递的即可,因为该过滤器正式对嵌入代码模块进行调用,而进行获取并将嵌入代码加以嵌入的。 15 | 16 | ### `StreamField`块的`EmbedBlock`类型 17 | 18 | 该`EmbedBlock`块类型允许将嵌入代码置于某个`StreamField`中。 19 | 20 | 比如: 21 | 22 | ```python 23 | from wagtail.embeds.blocks import EmbedBlock 24 | 25 | class MyStreamField(blocks.StreamBlock): 26 | ... 27 | 28 | embed = EmbedBlock() 29 | ``` 30 | 31 | ### `{% embed %}`标签 32 | 33 | 语法:`{% embed`元素”(举个例子)那么简单,因为Wagtail的多个组件 -- 同时涉及客户端与服务端 --都需要就如何处理那个功能达成一致,包括其如何暴露在编辑界面中、在数据库中应如何表示,以及在前端渲染时应如何被翻译出来(在功能适合渲染时)。 16 | 17 | Wagtail中富文本处理过程涉及到的组件有下面这些。 18 | 19 | ## 数据格式 20 | 21 | 富文本数据(由 [`RichTextField`](page_editing_interface.md#rich-text) 进行处理,而在 [`StreamField`](https://wagtail.xfoss.com/topics/streamfield.html) 中则是由 `RichTextBlock`进行处理),是以类似于HTML,但并不完全相同的方式,存储于数据库中的。比如到某个页面的链接,可能被存储为: 22 | 23 | ```html 24 |联络我们 获取更多信息。
25 | ``` 26 | 27 | 这里的`linktype`属性,表示了对该标签进行重写应使用的规则。在经由`|richtext`过滤器(参见 [富文本(过滤器)](https://wagtail.xfoss.com/topics/writing_templates.html#rich-text-filter))在某个模板上进行渲染时,这就会被转换成为一个有效的HTML: 28 | 29 | ```html 30 |联系我们 获取更多信息。
31 | ``` 32 | 33 | 在`RichTextBlock`情况下,块的值为一个`RichText`对象,在作为一个字符串而渲染时,将自动完成此转换,因此过滤器`|richtext`就无必要了。 34 | 35 | 与此类似,富文本内容中的某个图片,将像下面这样存储起来: 36 | 37 | ```html 38 | 39 | ``` 40 | 41 | 渲染时这将渲染为一个``元素: 42 | 43 | ```html 44 |
45 | ``` 46 | 47 | 再次,这里的`embedtype`属性表示了重写该标签所用的规则。除了``与``之外的所有其他标签,在转换后的HTML中都将保持不变。 48 | 49 | 有着一些应用到``与``的约束,他们的作用是实现经由字符串替换,而有效地完成转换: 50 | 51 | + 标签名称与属性必须是小写的 52 | + 属性值必须用双引号括起来 53 | + `embed`元素必须使用XML的自闭标签语法(XML self-closing tag syntax, 也就是以`/>`,而非``结束) 54 | + 属性值中仅允许这些HTML实体符号:`<`、`>`、`&`与`"` 55 | 56 | ## 功能注册 57 | 58 | 项目中的所有应用,都可定义对Wagtail的富文本处理过程的扩展,比如新的`linktype`与`embedtype`规则。名为 _功能注册_ 的对象,是作为有关富文本应如何运作的核心事实来源而加以提供的(An object known as the _feature registry_ serves as a central source of truth about how rich text should behave)。该对象可通过`register_rich_text_features`钩子进行访问,而该钩子是在启动时进行调用的,调用时会收集与富文本有关的所有定义: 59 | 60 | ```python 61 | # my_app/wagtail_hooks.py 62 | 63 | from wagtail.core import hooks 64 | 65 | @hooks.register('register_rich_text_features') 66 | def register_my_feature(features): 67 | # 这里将新的定义,添加到 “features” 68 | ``` 69 | 70 | ## 关于重写处理器 71 | 72 | 重写处理器,是一些知道如何将富文本标签的内容,诸如``与``,转换为前端HTML的类。比如`PageLinkHandler`类,就知道怎样将富文本标签``,转换为HTML标签``。 73 | 74 | 重写处理器还能提供到其他一些有关富文本标签的信息。比如对于一个给定的适当标签,`PageLinkHandler`就可用于提取出将引用哪个页面的信息。这对于可能需要那些富文本中所引用对象信息的下游代码,将是有用的。 75 | 76 | 可创建对之前定制的新`linktype`与`embedtype`进行支持的重写处理器。新的处理器必须是继承自`wagtail.core.richtext.LinkHandler`或`wagtail.core.richtext.EmbedHandler`的Python类。新的类应至少对下面的部分方法进行重写(这里列出的时`LinkHandler`的方法,不过`EmbedHandler`的这些方法也有着相同的签名): 77 | 78 | [`class LinkHandler`](#LinkHandler) 79 | 80 | + `identifier` 81 | 82 | 必需的。`identifier`属性是一个表示哪个富文本标签应由该处理器进行处理的字符串。 83 | 比如`PageLinkHandler.get_identifier`返回的字符串就是`"page"`,表明所有有着``的富文本标签,都将由其加以处理。 84 | 85 | + `expand_db_attributes(attrs)` 86 | 87 | 必需的。方法`expand_db_attributes`期望从某个数据库的富文本``标签(对于`EmbedHandler`就是`