Flask驅動的靜態站點生成器(譯)

{% include JB/setup %}html

翻譯自:Dead easy yet powerful static website generator with Flaskpython

純意譯……如下是正文,和jekyll很像的感受,哈?34行代碼完成一個靜態站點生成器。web


我想將個人在線身份統合到一個單獨的託管地方好久了,所以有了你如今瀏覽的這個網站。我也尋找一個靜態網站架構有段時間了,嘗試了許多但一個也不中意。這真使人沮喪。數據庫

而後遇到Armin Ronacher的這個tweetflask

<blockquote class="twitter-tweet tw-align-center"> <p>Frozen-Flask is really, really useful. Should have used that earlier.</p>&mdash; Armin Ronacher (@mitsuhiko) <a href="https://twitter.com/mitsuhiko/status/166570613295689728" data-datetime="2012-02-06T17:15:03+00:00">February 6, 2012</a> </blockquote>瀏覽器

ArminFlask這個Python微框架的做者,我喜歡flask的簡潔。因此這個tweet一個機靈,我便開始探索Frozen-Flask的玩法。服務器

Frozen-Flask將Flask應用_凍結_成靜態文件,這樣你可以高速而無痛地部署它們。再佐以Flask-FlatPages,你得到了完美的生成靜態站點工具集,這個站點將有因此你使用框架能獲得的特性。markdown

  • 酷的urls和簡單的路徑管理
  • 強大的模板
  • 本地動態服務
  • 靜態版本管理

第一輪:項目搭建

在新文件夾中建立個新的virtualenv,使用pip安裝必要的包:架構

$ mkdir sample_project && cd !$
$ mkvirtualenv --no-site-packages `pwd`/env
$ source env/bin/activate
$ pip install Flask Frozen-Flask Flask-FlatPages

寫咱們第一個版本的sitebuilder.pyapp

from flask import Flask
app = Flask(__name__)

@app.route("/")
def index():
    return "Hello World!"

if __name__ == "__main__":
    app.run(port=8000)

運行它;你應該看到相似:

$ python sitebuilder.py 
 * Running on http://127.0.0.1:8000/ 
 * Restarting with reloader

用瀏覽器打開_http://:127.0.0.1:8000_看是否正常。

又一輪:添加純文本頁面

Flask-FlatPages爲你的Flask應用提供一套頁面。相對動態頁面從關係數據庫構建,靜態頁面是從純文本文件構建。

在你的項目跟文件夾下建立一個pages/目錄,新建一個hello-wolrd.md扔進去:

$ mkdir pages $ vi pages/hello-world.md

hello-world.md文件:

title: Hello World
date: 2012-03-04

**Hello World**, from a *page*!

如你所見你能夠在頁面內容中寫入Markdown。因此讓咱們從新寫咱們的應用來爲經過文件名爲任何純文本提供服務。

from flask import Flask
from flask_flatpages import FlatPages

DEBUG = True
FLATPAGES_AUTO_RELOAD = DEBUG
FLATPAGES_EXTENSION = '.md'

app = Flask(__name__)
app.config.from_object(__name__)
pages = FlatPages(app)

@app.route('/')
def index():
    return "Hello World"

@app.route('/<path:path>/')
def page(path):
    return pages.get_or_404(path).html

if __name__ == '__main__':
    app.run(port=8000)

如今訪問http://127.0.0.1:8000/hello-world/將呈現渲染後的純文本。注意經過page對象得到html屬性markdown源碼被轉換成html。

又一輪:添加模板

flask使用jinja2模板引擎,讓咱們建立一些模板來裝飾頁面。首先在項目根目錄下建立一個templates文件夾:

$ mkdir templates

templates/base.html中建立基本佈局:

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title>My site</title>
</head>
<body>
    <h1><a href="{{ url_for("index") }}">My site</a></h1>
{% block content %}
    <p>Default content to be displayed</p>
{% endblock content %}
</body>
</html>

注意url_for()這個模板函數,這是咱們使用Flask和Jinjia2生成url的方式。

如今用page.html模板來填充頁面內容的佈局:

{% extends "base.html" %}

{% block content %}
    <h2>{{ page.title }}</h2>
    {{ page.html|safe }}
{% endblock content %}

咱們的應用如今應該是:

from flask import Flask, render_template
from flask_flatpages import FlatPages

DEBUG = True
FLATPAGES_AUTO_RELOAD = DEBUG
FLATPAGES_EXTENSION = '.md'

app = Flask(__name__)
app.config.from_object(__name__)
pages = FlatPages(app)

@app.route('/')
def index():
    return "Hello World"

@app.route('/<path:path>/')
def page(path):
    page = pages.get_or_404(path)
    return render_template('page.html', page=page)

if __name__ == '__main__':
    app.run(port=8000)

見鬼,咱們剛剛作了什麼?

  • 建立了一個應用的模板;一個通用佈局(base.html)和一個頁面模板(page.html)
  • 咱們使用render_template函數對頁面用頁面模板裝飾。
  • 頁面模板擴展基本模板來避免在每一個頁面都複製粘帖相同的內容。

又一輪:在主頁呈現頁面列表

如今咱們的主頁弱爆了。咱們讓它列出全部存在的頁面。

建立一個templates/index.html

{% extends "base.html" %}

{% block content %}
    <h2>List of stuff</h2>
    <ul>
    {% for page in pages %}
        <li>
            <a href="{{ url_for("page", path=page.path) }}">{{ page.title }}</a>
        </li>
    {% else %}
        <li>No stuff.</li>
    {% endfor %}
    </ul>
{% endblock content %}

隨意地建立更多純文本頁面,就像咱們建立hello-world.md同樣,將文件保存在pages/目錄下,使用.md擴展名。

咱們應用中的index()路徑如今應該這樣:

重載主頁,頁面列表將呈現。真他×簡單。

又一輪:給頁面添加元數據

Flask-FlatPages容許像咱們建立和hello-world.md的標題和日期同樣添加元數據,而且經過page.meta來存取它們,得到看上去蠢蠢的python字典。真使人吃驚,不是嗎?

讓咱們假設想要給頁面添加標籤,咱們的hello-world.md將變成:

title: Hello World
date: 2012-03-04
tags: [general, awesome, stuff]

**Hello World**, from a *page*!

元數據用YAML描述,所以你可以使用字符串、布爾、整數、浮點、列表、甚至字典,它們將轉換成Python相應的內在等價物。

咱們將使用兩個包含共享部分的不一樣的模板來列出普通頁面和標籤頁面,index.html如今應該是:

{% extends "base.html" %}

{% block content %}
    <h2>List of stuff</h2>
    {% with pages=pages  %}
        {% include "_list.html" %}
    {% endwith %}
{% endblock content %}

建立tag.html模板,它將用來呈現標籤頁面列表:

{% extends "base.html" %}

{% block content %}
    <h2>List of stuff tagged <em>{{ tag }}</em></h2>
    {% with pages=pages  %}
        {% include "_list.html" %}
    {% endwith %}
{% endblock content %}

新建的_list.html模板應該包含:

<ul>
{% for page in pages %}
    <li>
        <a href="{{ url_for("page", path=page.path) }}">{{ page.title }}</a>
    {% if page.meta.tags|length %}
        | Tagged:
        {% for page_tag in page.meta.tags %}
            <a href="{{ url_for("tag", tag=page_tag) }}">{{ page_tag }}</a>
        {% endfor %}
    {% endif %}
    </li>
{% else %}
    <li>No page.</li>
{% endfor %}
</ul>

嚮應用中添加新的tag路徑,使用新的tag.html模板:

@app.route('/tag/<string:tag>/')
def tag(tag):
    tagged = [p for p in pages if tag in p.meta.get('tags', [])]
    return render_template('tag.html', pages=tagged, tag=tag)

注:若你以前不喜歡python的列表推導式,如今你會了。

又一輪:生成靜態頁面

好的,如今咱們只要有一個動態網站,爲存儲在文件系統上的純文本頁面提供服務:廢話。可是咱們固然不是Flask應用而是一堆靜態文件,省去了任何應用服務器。

來進入Frozen-Flask。它的使用真××簡單:

import sys

from flask import Flask, render_template
from flask_flatpages import FlatPages
from flask_frozen import Freezer

DEBUG = True
FLATPAGES_AUTO_RELOAD = DEBUG
FLATPAGES_EXTENSION = '.md'

app = Flask(__name__)
app.config.from_object(__name__)
pages = FlatPages(app)
freezer = Freezer(app)

@app.route('/')
def index():
    return render_template('index.html', pages=pages)

@app.route('/tag/<string:tag>/')
def tag(tag):
    tagged = [p for p in pages if tag in p.meta.get('tags', [])]
    return render_template('tag.html', pages=tagged, tag=tag)

@app.route('/<path:path>/')
def page(path):
    page = pages.get_or_404(path)
    return render_template('page.html', page=page)

if __name__ == '__main__':
    if len(sys.argv) > 1 and sys.argv[1] == "build":
        freezer.freeze()
    else:
        app.run(port=8000)

而後運行:

$ python sitebuilder.py build

打開構建文件夾鍵入以下命令:

$ tree
.
├── hello-world
│   └── index.html
├── index.html
└── tag
    ├── awesome
    │   └── index.html
    ├── general
    │   └── index.html
    └── stuff
        └── index.html

5 directories, 5 files

想法:嚇壞了

你如今能部署build目錄下的任何文件到任何能託管靜態文件的地方了,而你僅僅用34行Python代碼就完成了……不錯吧?

固然,如今的版本弱爆了,你能一點一點的爲它添加各類特性了。

相關文章
相關標籤/搜索