教程:构建简单的博客#
在本教程中,我们将构建一个简单的博客,其条目存储在数据库中。然后,我们将渲染这些帖子在服务器上并直接向用户提供 HTML。
本教程旨在作为在 Quart 中构建服务器渲染网站的入门介绍。如果你想跳到最后,代码位于 Github 上。
1:创建项目#
我们需要为我们的博客服务器创建一个项目,我喜欢使用 Poetry 来完成此操作。Poetry 通过 pip(或通过 Brew)安装。
pip install poetry
然后,我们可以使用 Poetry 创建一个新的博客项目
poetry new --src blog
现在可以在 blog 目录中开发我们的项目,所有后续命令都应在运行 blog 目录中执行。
2:添加依赖项#
要开始,我们只需要 Quart 来构建博客服务器,我们可以通过运行以下命令将其安装为项目的依赖项。
poetry add quart
Poetry 将通过运行以下命令来确保此依赖项存在且路径正确。
poetry install
3:创建应用程序#
我们需要一个 Quart 应用程序作为我们的 Web 服务器,这是通过以下添加到 src/blog/__init__.py 中创建的。
from quart import Quart
app = Quart(__name__)
def run() -> None:
app.run()
为了使应用程序易于运行,我们可以通过以下添加到 pyproject.toml 中,从诗歌脚本调用 run 方法。
[tool.poetry.scripts]
start = "blog:run"
这允许以下命令启动应用程序
poetry run start
4:创建数据库#
有许多数据库管理系统可供选择,具体取决于需求和要求。在这种情况下,我们只需要最简单的系统,Python 的标准库包含 SQLite,使其成为最容易的。
要初始化数据库,我们需要以下 SQL 来创建正确的表,并将其添加到 src/blog/schema.sql 中
DROP TABLE IF EXISTS post;
CREATE TABLE post (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
'text' TEXT NOT NULL
);
接下来,我们需要能够在命令中创建数据库,我们可以通过将命令代码添加到 src/blog/__init__.py 中来实现。
from pathlib import Path
from sqlite3 import dbapi2 as sqlite3
app.config.update({
"DATABASE": app.root_path / "blog.db",
})
def _connect_db():
engine = sqlite3.connect(app.config["DATABASE"])
engine.row_factory = sqlite3.Row
return engine
def init_db():
db = _connect_db()
with open(app.root_path / "schema.sql", mode="r") as file_:
db.cursor().executescript(file_.read())
db.commit()
接下来,我们需要更新 pyproject.toml 中的诗歌脚本,如下所示。
[tool.poetry.scripts]
init_db = "blog:init_db"
start = "blog:run"
现在,我们可以运行以下命令来创建和更新数据库。
poetry run init_db
警告
运行此命令将擦除任何现有数据。
5:在数据库中显示帖子#
现在,我们可以显示数据库中存在的帖子。为此,我们首先需要一个模板来将帖子渲染为 HTML。这如下所示,应添加到 src/blog/templates/posts.html 中
<main>
{% for post in posts %}
<article>
<h2>{{ post.title }}</h2>
<p>{{ post.text|safe }}</p>
</article>
{% else %}
<p>No posts available</p>
{% endfor %}
</main>
现在,我们需要一个路由来查询数据库,检索消息并渲染模板。如以下代码所示,应将其添加到 src/blog/__init__.py 中
from quart import render_template, g
def _get_db():
if not hasattr(g, "sqlite_db"):
g.sqlite_db = _connect_db()
return g.sqlite_db
@app.get("/")
async def posts():
db = _get_db()
cur = db.execute(
"""SELECT title, text
FROM post
ORDER BY id DESC""",
)
posts = cur.fetchall()
return await render_template("posts.html", posts=posts)
6:创建新帖子#
要创建博客帖子,我们首先需要一个表单,用户可以在其中输入帖子详细信息。这是通过以下模板代码完成的,应将其添加到 src/blog/templates/create.html 中
<form method="POST" style="display: flex; flex-direction: column; gap: 8px; max-width:400px">
<label>Title: <input type="text" size="30" name="title" /></label>
<label>Text: <textarea name="text" rows="5" cols="40"></textarea></label>
<button type="submit">Create</button>
</form>
样式确保表单的元素以垂直方式排列,并带有间隙和合理的最大宽度。
要允许访问者创建博客帖子,我们需要接受此表单在浏览器中生成的 POST 请求。为此,以下内容应添加到 src/blog/__init__.py 中
from quart import redirect, request, url_for
@app.route("/create/", methods=["GET", "POST"])
async def create():
if request.method == "POST":
db = _get_db()
form = await request.form
db.execute(
"INSERT INTO post (title, text) VALUES (?, ?)",
[form["title"], form["text"]],
)
db.commit()
return redirect(url_for("posts"))
else:
return await render_template("create.html")
此路由处理程序将针对 GET 请求(例如,通过浏览器中的导航)渲染创建表单。但是,对于 POST 请求,它将提取表单数据以创建博客帖子,然后将用户重定向到包含帖子的页面。
7:测试#
要测试我们的应用程序,我们需要检查是否可以创建博客帖子,以及创建后是否在帖子页面上显示。首先,我们需要创建一个用于测试的临时数据库,我们可以使用放置在 tests/conftest.py 中的 pytest 夹具来实现。
import pytest
from blog import app, init_db
@pytest.fixture(autouse=True)
def configure_db(tmpdir):
app.config['DATABASE'] = str(tmpdir.join('blog.db'))
init_db()
此夹具将在我们的测试之前自动运行,从而设置一个我们可以在测试中使用的数据库。
要测试创建和显示,我们可以将以下内容添加到 tests/test_blog.py 中
from blog import app
async def test_create_post():
test_client = app.test_client()
response = await test_client.post("/create/", form={"title": "Post", "text": "Text"})
assert response.status_code == 302
response = await test_client.get("/")
text = await response.get_data()
assert b"<h2>Post</h2>" in text
assert b"<p>Text</p>" in text
由于测试是一个异步函数,我们需要通过运行以下命令安装 pytest-asyncio。
poetry add --dev pytest-asyncio
安装完成后,需要通过以下添加到 pyproject.toml 中来配置。
[tool.pytest.ini_options]
asyncio_mode = "auto"
最后,我们可以通过以下命令运行测试。
poetry run pytest tests/
如果您在 Quart 示例文件夹中运行此命令,则需要添加 -c pyproject.toml
选项以防止 pytest 使用 Quart pytest 配置。
8:总结#
我们构建了一个简单的数据库支持的博客服务器。这应该是构建任何类型的服务器渲染应用程序的良好起点。