创建一个博客
创建一个博客#
前言#
文档的这一部分将包含各种教程。这些指南旨在引导您从头到尾使用 Masonite 构建各种类型的项目。我们可能不会详细解释每一节的内容,因为文档的这一部分只是为了让您熟悉 Masonite 的内部工作原理。
因为文档的这一部分是为了让您能够使用 Masonite 编写代码,任何需要进一步说明的地方都在不同的「提示块」中。完成本教程后,或者只是想了解更多关于某个主题的信息,建议您仔细阅读每个提示块,然后按照链接深入阅读参考文档,这将大大提高解释力。
提示块#
在整个教程中,您将看到各种提示块。下面是各种颜色所代表的示例。
如果您想了解有关当前正在讨论的主题的更多信息,您将看到绿色的提示块。
你还会看到蓝色的提示块。这些不应该被忽略,通常包含需要进一步理解的背景信息。
安装#
本教程假设您已经安装了 Masonite 。如果没有,请务必阅读 安装 指南,以便重新安装并运行 Masonite 。一旦你启动运行了一个,或者如果你已经有正在运行的,请继续。
创建一个博客#
在本教程中,我们将介绍如何创建博客。我们将介绍 Masonite 的所有主要系统,它应该会让您有信心尝试更高级的教程或自己构建一个应用程序。
路由#
通常, Masonite 开发流程的第一步是创建一个路由。所有路由都位于 routes/web.py
中,非常容易理解。它们由请求方法和路由方法组成。路由只是说明传入的 URI 应该指向哪个控制器。
例如,要创建 GET
请求路由,它将如下所示:
routes/web.py
from masonite.routes import Get
Get('/url', 'Controller@method')
我们稍后再谈控制器。
您可以在 路由 文档中阅读有关路由的更多信息
创建我们的路由:#
我们将首先创建一个视图和控制器来创建一篇博客文章。
控制器是一个包含控制器方法的简单类。这些控制器方法将成为我们的路由所调用的方法,因此它们将包含应用程序的所有业务逻辑。
如果您了解 Django 框架,可以将控制器方法看作
views.py
文件中的函数
现在让我们创建第一条路由。我们可以将所有路由放在 routes/web.py
和 ROUTES
列表中。你会看到我们有一个主页的路由。让我们添加一个创建博客的路径。
routes/web.py
ROUTES = [
Get('/', 'WelcomeController@show').name('welcome'),
# 博客的路由
Get('/blog', 'BlogController@show')
]
你会注意到这里有一个 BlogController@show
字符串。这意味着「使用 blog 控制器的 show 方法来呈现这个路由」。这里唯一的问题是我们还没有博客控制器。
让我们在下一步中创建
BlogController
:第 2 部分 - 创建我们的第一个控制器
创建控制器#
所有控制器都位于 app/http/controllers
目录中, Masonite 为每个文件升级一个控制器。这对于更大的应用程序开发是有效的,因为大多数开发人员使用具有高级搜索功能的文本编辑器,如 Sublime 、 VSCode 或 Atom 。在这个实例中,在类之间切换很简单,可以促进更快的开发。很容易记住控制器的确切位置,因为文件名就是控制器。
当然,您可以随意移动控制器,但 craft 命令行工具将默认将它们放在单独的文件中。如果你觉得这很奇怪的话,不妨试试看你是否喜欢这种固执的布局。
创建我们的第一个控制器#
像 Masonite 的大多数部分一样,您可以使用 craft 命令构建控制器:
$ craft controller Blog
这将在 app/http/controllers
目录中创建一个如下所示的控制器:
app/http/controller/BlogController.py
""" BlogController 模块。"""
from masonite.request import Request
from masonite.view import View
from masonite.controllers import Controller
class BlogController(Controller):
""" BlogController 控制器类"""
def __init__(self, request: Request):
""" BlogController 初始化程序
参数:
request {masonite.request.Request} -- Masonite 请求类。
"""
self.request = request
def show(self, view: View):
pass
很简单,对吧?你会注意到我们在寻找一个 show
方法。这些称为「控制器方法」,类似于 Django 所说的「视图」
但也要注意,我们现在有了前面在路由中指定的 show 方法。
返回视图#
我们可以在控制器中返回很多不同的东西,但是现在我们可以从控制器返回一个视图。 Masonite 中的视图是 html 文件或「模板」。它们本身不像其他 Python 框架那样是 Python 对象。视图是用户将看到 (或查看) 的内容。
这很重要,因为这是我们对 Python 的 IOC 容器的第一次介绍。我们在参数列表中指定我们需要一个视图类, Masonite 将为我们注入它。
现在我们不再关注整个控制器,而只关注我们担心的部分。 ...
意味着在代码之间有一些我们不担心的东西:
app/http/controllers/BlogController.py
from masonite.view import View
...
def show(self, view: View):
return view.render('blog')
注意这里我们「提示」了 View
类。这就是 Masonite 所说的「自动解析依赖注入」。如果你现在不明白,别担心。你读得越多,你就越能理解。
一定要了解更多关于服务容器的信息。
创建我们的视图#
现在您会注意到,我们正在返回 blog
视图,但它还不存在。
所有视图都在 resources/templates
目录中。我们可以创建一个名为 resources/templates/blog.html
的新文件,也可以使用另一个 craft 命令:
$ craft view blog
这将为我们创建上述模板。
我们可以在这个文件中添加一些文本,如:
resources/templates/blog.html
这是一个博客
然后运行服务器
$ craft serve
打开 http://localhost:8000/blog
。你将在你的浏览器中看到「这是一个博客」。
身份验证#
大多数应用程序都需要某种形式的身份验证。 Masonite 附带了一个 craft 命令,可以为您构建一个身份验证系统。这通常应该在新安装的 Masonite 上运行,因为它将为您创建控制器路由和视图。
对于我们的博客,我们需要设置某种形式的注册,以便我们可以让新用户开始发布文章到我们的博客。我们可以通过运行 craft 命令创建身份验证系统:
$ craft auth
我们应该会得到一个成功的消息,说明创建了一些新资产。你可以检查你的 controllers 文件夹,你应该会看到一些新的控制器,它们应该可以处理注册。
我们将稍后检查为我们创建的内容。
数据库设置#
为了注册这些用户,我们需要一个数据库。希望您已经有了某种本地数据库设置,如 MySQL 或 Postgres ,但我们假设您没有。在这种情况下,我们可以使用 SQLite。
现在我们需要更改一些环境变量,以便 Masonite 可以创建 SQLite 数据库。
这些环境变量可以在根目录的.env
文件中找到。打开该文件,您可以看到如下内容:
.env
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=masonite
DB_USERNAME=root
DB_PASSWORD=root
继续更改这些连接设置,方法是将 sqlite
添加到 DB_CONNECTION
变量,以及将要在迁移时为您创建的数据库中添加的任何内容。我们将其称为 blog.db
:
.env
DB_CONNECTION=sqlite
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=blog.db
DB_USERNAME=root
DB_PASSWORD=root
迁移#
设置正确的凭据后,我们可以继续迁移数据库。开箱即用,Masonite 具有一个针对 users 表的迁移,它将成为我们用户的基础。您可以在迁移之前编辑,但是默认配置可以更好地满足大多数需求,您以后可以随时添加或删除。
$ craft migrate
这将为我们创建用户表以及迁移表,以跟踪我们以后添加的所有迁移。
创建用户#
现在我们已经有了身份验证和所有迁移,现在让我们创建第一个用户。请记住,我们运行了 craft auth
,所以我们有一些新的模板和控制器。
继续运行服务器:
$ craft serve
然后转到 localhost:8000/register 并填写表单。您可以使用您喜欢的任何名称和电子邮件,但为此目的,我们将使用:
Username: demo
Email: demo@email.com
Password: password
迁移#
既然我们已经设置了身份验证,并且已经适应了迁移,那么让我们创建一个新的迁移来存储我们的帖子。
我们的 posts 表应该有几个明显的列,我们将在本教程中简化这些列。让我们来看看我们是如何用 Masonite 创造迁移的。
Craft 命令#
毫不奇怪,我们有一个 craft 命令来创建迁移。您可以阅读更多关于 数据库迁移 的信息,但我们会将其简化为命令,并解释一些正在发生的事情:
$ craft migration create_posts_table --create posts
这个命令只是创建迁移的开始,迁移将创建 posts 表。按照惯例,表名应该是复数的 (模型名应该是单数,后面会详细介绍)。
这将在 databases/migrations
文件夹中创建迁移。让我们打开它,从第 6 行开始,我们应该会看到这样的东西:
databases/migrations/2018_01_09_043202_create_posts_table.py
def up(self):
"""
运行迁移。
"""
with self.schema.create('posts') as table:
table.increments('id')
table.timestamps()
让我们在 posts 表中添加一个标题、一个作者和一个主体。
databases/migrations/2018_01_09_043202_create_posts_table.py
def up(self):
"""
运行迁移。
"""
with self.schema.create('posts') as table:
table.increments('id')
table.string('title')
table.integer('author_id').unsigned()
table.foreign('author_id').references('id').on('users')
table.string('body')
table.timestamps()
这应该很简单,但如果您想了解更多,请务必阅读 [数据库迁移](orator-orm/ Database -migration .md) 文档。
现在我们可以 migrate 这个迁移来创建 posts 表
$ craft migrate
模型#
现在我们已经完成了表和迁移,并有了 posts 表,接下来创建一个模型。
Masonite 中的模型与其他 Python 框架稍有不同。 Masonite 使用 Orator ,这是 ORM 的一个积极的记录实现。这基本上意味着我们不会构建我们的模型,然后将其转化为迁移。模型和迁移在 Masonite 中是分开的。不管表是什么样子的,我们的模型都将形成表的形状。
创建我们的模型#
同样,我们可以使用 craft 命令创建模型:
$ craft model Post
注意我们的模型用的是单数形式。默认情况下, Orator 会在我们的数据库(在本例中为 posts )中检查类的复数名称,方法是在模型中添加一个「s」。我们稍后将讨论如何显式地指定表。
创建的模型位于在 app/Post.py
中。当我们打开它时,它应该是这样的:
app/Post.py
""" Post 数据库模型。"""
from config.database import Model
class Post(Model):
pass
很简单,对吧?如前所述,我们不必操纵模型。在创建或更改迁移时,模型将形成表的形状。
表名#
同样,模型所附加的表名是模型 \ 的复数形式 (通过添加 “s” ),但是如果您调用表,则可以使用诸如 “ blog” 而不是 “ blogs” 之类的其他名称,我们可以指定表名:
app/Post.py
"""A Post Database Model."""
from config.database import Model
class Post(Model):
__table__ = 'blog'
批量分配#
默认情况下,Orator 可以防止批量分配,这是一项安全措施,因此我们需要明确设置希望填充的列:
app/Post.py
"""A Post Database Model."""
from config.database import Model
class Post(Model):
__fillable__ = ['title', 'author_id', 'body']
关系#
这种关系在这里很简单。请记住,我们在迁移中创建了外键。我们可以在模型中创建该关系,如下所示:
app/Post.py
"""A Post Database Model."""
from config.database import Model
from orator.orm import belongs_to
class Post(Model):
__fillable__ = ['title', 'author_id', 'body']
@belongs_to('author_id', 'id')
def author(self):
from app.User import User
return User
由于 Masonite 的建模方式,某些模型可能会相互依赖,因此最好像上述那样在关系内执行导入,以防止任何可能的循环导入。
我们不会在这里详细介绍不同类型的关系,如要了解更多信息,请阅读 ORM 文档。
设计我们的博客#
让我们创建一个 HTML 模板,以便我们可以进一步了解视图的工作方式。在这一部分中,先创建一个基本模板,当我们学到足够的 HTML 基础知识后,您可以继续并创建一个非常出色的博客模板 (或从 Internet 上收集一个)。
现在我们有了模型和迁移设置,也拥有了页面布局和更新博客文章所需的所有后端。
我们还将在创建模板之前检查用户是否已登录。
创建模板#
创建的 URL 将位于 / blog / create
,一个简单的博客文章模板:
resources/templates/blog.html
<form action="/blog/create" method="POST">
{{ csrf_field }}
<input type="name" name="title">
<textarea name="body"></textarea>
</form>
请注意,这里要填写 {{csrf_field}}
。 Masonite 带有 CSRF 保护,因此我们需要使用 CSRF 字段来渲染一个令牌。
现在,因为我们的 posts 表中有一个外键,所以我们需要确保用户在创建前已登录,让我们稍微修改一下模板:
resources/templates/blog.html
{% if auth() %}
<form action="/blog/create" method="POST">
{{ csrf_field }}
<label> Title </label>
<input type="name" name="title"><br>
<label> Body </label>
<textarea name="body"></textarea>
<input type="submit" value="Post!">
</form>
{% else %}
<a href="/login">Please Login</a>
{% endif %}
auth()
是一个视图辅助函数,它要么返回当前用户,要么返回 None
。
Masonite 使用 Jinja2 模板, 如果您对这个模板引擎还不熟悉,阅读 Jinja2 模板 文档
静态文件#
为了简单起见,我们不去使用类似 Bootstrap 美化我们的博客。但是了解 Masonite 如何引入诸如 CSS 文件之类的静态文件是非常有必要的。接下来我们逐步了解如何添加 CSS 文件到我们的博客中。
首先,进入 storage/static/
目录创建 blog.css
文件,并在文件内添加任何您喜欢的样式。 在这里,我们将 html 页面显示为灰色。
storage/static/blog.css
html {
background-color: #ddd;
}
现在我们在模板文件顶部引入该文件。
resources/templates/blog.html
<link href="/static/blog.css" rel="stylesheet">
{% if auth() %}
<form action="/blog/create" method="POST">
{{ csrf_field }}
<label> Title </label>
<input type="name" name="title"><br>
<label> Body </label>
<textarea name="body"></textarea>
<input type="submit" value="Post!">
</form>
{% else %}
<a href="/login">Please Login</a>
{% endif %}
静态文件引入非常简单,了解它们的工作原理非常重要。在本教程中,我们将重点放在后端。
Javascript 文件引入也类似:
resources/templates/blog.html
<link href="/static/blog.css" rel="stylesheet">
{% if auth() %}
<form action="/blog/create" method="POST">
{{ csrf_field }}
<label> Title </label>
<input type="name" name="title"><br>
<label> Body </label>
<textarea name="body"></textarea>
<input type="submit" value="Post!">
</form>
{% else %}
<a href="/login">Please Login</a>
{% endif %}
<script src="/static/script.js"></script>
关于静态文件的更多知识,参考 静态文件
用于创建的控制器和容器#
请注意,我们的操作将跳转到 /blog/create
,因此我们需要将路由定向到我们的控制器方法。在这个教程中,我们会将其定向到 store
方法。
我们打开 routes/web.py
文件并创建一个路由,将其添加到 ROUTES
列表:
routes/web.py
from masonite.routes import Get, Post
...
Post('/blog/create', 'BlogController@store'),
并在我们的控制器上创建一个 store 方法:
app/http/controllers/BlogController.py
...
def show(self, view: View):
return view.render('blog')
# New store Method
def store(self):
pass
从上面的表单中可以看到,我们将接受两个表单输入:title 和 body 。因此,让我们导入 Post
模型并使用输入数据创建一篇文章。
app/http/controllers/BlogController.py
from app.Post import Post
from masonite.request import Request
...
def store(self, request: Request):
Post.create(
title=request.input('title'),
body=request.input('body'),
author_id=request.user().id
)
return 'post created'
请注意,我们现在在此处使用了 request:Request
。这是 Request
对象。这个是从哪里来的?这是 Masonite 的强大和美妙之处,也是对 服务容器 的首次介绍。 服务容器 是一种非常强大的实现,因为它允许您向 Masonite 询问对象 (在这种情况下为 Request
) 并获取该对象。这是一个重要的概念,因此请务必进一步阅读文档。
在此处阅读有关 [服务容器] 的更多信息 (architectural-concepts /service-container.md)。
请注意这里我们使用了 Input()
方法。Masonent 不区分请求方法,因此是否使用 GET
或 POST
请求并不重要。您可以始终使用此方法。
继续使用 craft serve 运行服务器,然后转到 http://localhost:8000/blog
并创建帖子。这里应该使用 post
请求方法到 /blog/create
路径,我们应该看到 “post Created”。
显示我们的帖子#
让我们继续并展示如何显示我们刚刚创建的帖子。在本部分中,我们将创建 2 个新模板来显示所有帖子和特定帖子。
创建模板#
让我们创建 2 个新模板。
$ craft view posts
$ craft view single
让我们从显示所有帖子开始
创建控制器#
让我们创建一个新控制器,以将其与 BlogController
分开。
$ craft controller Post
因此,现在在我们的 show
方法中,我们将显示所有帖子,然后创建一个 single
的方法来显示特定的帖子。
显示方法#
在 show
方法中返回包含所有帖子的帖子视图:
app/http/controllers/PostController.py
from app.Post import Post
...
def show(self, view: View):
posts = Post.all()
return view.render('posts', {'posts': posts})
帖子路由#
我们需要为此方法添加路由:
routes/web.py
Get('/posts', 'PostController@show')
路由视图#
我们的文章视图非常简单:
resources/templates/posts.html
{% for post in posts %}
{{ post.title }}
<br>
{{ post.body }}
<hr>
{% endfor %}
继续运行服务器,然后访问 http://localhost:8000/posts
链接。您应该可以看到文章的列表。如果只看到一个,那去 http://localhost:8000/blog
去创建更多内容吧。
显示作者#
我们之前创建了作者和文章的关系。Oator 将采用这种关系并建立属性,因此我们可以显示作者的姓名:
resources/templates/posts.html
{% for post in posts %}
{{ post.title }} by {{ post.author.name }}
<br>
{{ post.body }}
<hr>
{% endfor %}
接下来让我们重复这个过程,稍微改变一下来实现单篇文章展示。
单篇文章#
接下来,我们只显示一篇文章。我们需要新增一个路由:
routes/web.py
Get('/post/@id', 'PostController@single')
请注意这里有一个 @id
字符串。我们将会在下一部分在控制器中获取 URL 部分使用它。
Single 方法#
让我们创建一个 single
方法来显示单篇文章。
app/http/controllers/PostController.py
from app.Post import Post
from masonite.request import Request
from masonite.view import View
...
def single(self, view: View, request: Request):
post = Post.find(request.param('id'))
return view.render('single', {'post': post})
我们使用 param()
方法从 URL 中获取 id 。这个 id 就是上面我们在路由中指定的 @id
。
在项目里,我们一般会用类似
@slug
的操作 ,然后用request().param('slug')
获取。
单篇文章展示#
现在只需要显示一篇文章,所以我们写一个简单的视图文件即可:
resources/templates/single.html
{{ post.title }}
<br>
{{ post.body }}
<hr>
运行服务器,并访问 http://localhost:8000/post/1
和 http://localhost:8000/post/2
,将会看到不同的文章。
更新和删除文章#
目前为止,我们花费了一些时间来讨论上面的逻辑。接下来让我们快速完成更新和删除文章。我们假设您已经掌握了上面的知识,这部分的内容大同小异。
更新方法#
让我们在 PostController
文件里新增更新方法。
app/http/controllers/PostController.py
def update(self, view: View, request: Request):
post = Post.find(request.param('id'))
return view.render('update', {'post': post})
def store(self, request: Request):
post = Post.find(request.param('id'))
post.title = request.input('title')
post.body = request.input('body')
post.save()
return 'post updated'
我们已经对控制器比较熟悉,所以一次性写了两个方法 update
和 store
。我们用 update
方法来展示一个表单,用 store
实现更新入库。
创建视图文件#
$ craft view update
resources/templates/update.html
<form action="/post/{{ post.id }}/update" method="POST">
{{ csrf_field }}
<label for="">Title</label>
<input type="text" name="title" value="{{ post.title }}"><br>
<label>Body</label>
<textarea name="body">{{ post.body }}</textarea><br>
<input type="submit" value="Update">
</form>
创建路由#
我们新增了两个控制器方法,现在将它们附加到路由文件中。
routes/web.py
Get('/post/@id/update', 'PostController@update'),
Post('/post/@id/update', 'PostController@store'),
就是这样!现在,我们可以更新我们的文章了。
删除方法#
让我们更进一步,新增一个 delete 方法。
app/http/controllers/PostController.py
from masonite.request import Request
...
def delete(self, request: Request):
post = Post.find(request.param('id'))
post.delete()
return 'post deleted'
删除路由#
routes/web.py
Get('/post/@id/delete', 'PostController@delete'),
注意为了简单起见,我们在这里使用了 GET
路由,使用 POST
方法会更好。我们在更新页面上添加一个链接,该链接将删除该文章。
更新模板#
我们可以在更新模板中直接添加一个删除链接:
resources/templates/update.html
<form action="/post/{{ post.id }}/update" method="POST">
{{ csrf_field }}
<label for="">Title</label>
<input type="text" name="title" value="{{ post.title }}"><br>
<label>Body</label>
<textarea name="body">{{ post.body }}</textarea><br>
<input type="submit" value="Update">
<a href="/post/{{ post.id }}/delete"> Delete </a>
</form>
太棒了!现在,您有了一个博客,可用于创建,查看,更新和删除帖子!继续探索吧!
本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
推荐文章: