创建一个博客

未匹配的标注

本节的文档将包含各种教程。这些教程旨在引导您从零开始使用Masonite构建各种类型的项目。我们可能不会对每个部分都进行十分详细的解释,因为文档的这一部分只是为了让您熟悉Masonite的工作原理。

由于文档的这一部分旨在帮助您熟悉Masonite并使用它进行编码工作,因此拓展性信息都在“提示块”中。一旦您对某个信息有疑问或想深入了解的话,建议您仔细阅读对应的提示块并按照链接深入参考文档,后者会做更多的解释。

提示块

您将在整个文档中看到各种提示块。下面是各种颜色表示的示例。

提示:您将看到绿色的提示块,如果您想了解有关当前讨论的主题的更多信息,则应遵循这些提示块。

提示:您还将看到蓝色的提示块。这些内容不应被忽略,并且通常包含您需要进一步了解的背景信息。

安装

本教程是基于假设您已经安装了Masonite进行讲解的。如果您还没有安装Masonite,请阅读文档《Masonite 介绍和安装》章节进行操作;反之,请继续阅读文档。

创建博客

在本节教程中,我们将介绍如何创建博客以及Masonite的系统结构,学习完之后您应该可以独立的使用它构建应用程序。

路由

通常,使用Masonite进行开发的第一个起点是创建路由。所有路由规则都包含在routes/web.py这个文件中。它们由请求方法和路由方法组成。路由只是说明传入URI应该指向哪些控制器。

例如,要创建 GET请求路由,它将如下所示:

routes/web.py

from masonite.routes import Route

ROUTES = [
    Route.get('/url', 'Controller@method')
]

稍后我们将详细介绍控制器。

提示:你可以通过阅读 路由 这节文档了解关于路由的更多信息。

创建路由规则

我们将从如何创建视图和控制器开始讲解博客文章页面的开发。

控制器是从Masonite的控制器类继承并包含控制器方法的简单类。这些控制器方法将是我们的路由将调用的方法,因此它们将包含我们应用程序的大部分业务逻辑。

提示:如果您使用过Django框架的话,那么可以将控制器方法视为views.py文件中的函数。

我们可以将所有路由规则放在routes/web.pyROUTES列表中。默认会有一条主页的路由规则。现在添加一条博客的路由开始我们的编码。

routes/web.py

ROUTES = [
    Route.get('/', 'WelcomeController@show').name('welcome'),

    # Blog Routes
    Route.get('/blog', 'BlogController@show')
]

您会注意到,这里有一个BlogController@show字符串。这意味着「这条路由规则的访问路径是blog控制器的show方法」。这里唯一的问题是我们还没有博客控制器。

创建控制器

默认情况下,所有控制器都位于app/controllers目录中,并且 Masonite 为每个文件结构升级一个控制器。事实证明,这对于大型应用程序开发非常有效,因为大多数开发人员使用具有高级搜索功能的文本编辑器,例如 Sublime、VSCode 或 Atom。在这种情况下,类之间的切换很简单,并且可以促进更快的开发。很容易记住控制器的确切位置,因为文件名就是控制器。

当然,您可以将控制器移动到任何您喜欢的地方,但craft命令行工具将默认将其放在单独的文件中。如果您觉得这很奇怪,那么不妨尝试一下,看看您是否喜欢这种固执己见的布局。

创建我们的第一个控制器

与Masonite的大多数使用者一样,您可以使用craft命令构建控制器:

terminal

$ python craft controller Blog

这将在app/controllers目录中创建如下所示的控制器:

app/http/controller/BlogController.py

from masonite.controllers import Controller
from masonite.views import View

class BlogController(Controller):
    def show(self, view: View):
        return view.render("")

很简单,对吧?你会注意到我们在寻找一个 show 方法。这些称为「控制器方法」,类似于 Django 所说的「视图」

但也要注意,我们现在有了前面在路由中指定的 show 方法。

返回视图

我们可以在控制器中返回很多不同的东西,但现在我们可以从控制器中返回一个视图。 Masonite 中的视图是 html 文件或「模板」。 它们本身不像其他 Python 框架那样是 Python 对象。 视图是用户将看到的 \ (或视图\)。

这是我们第一次介绍 Masonite 的 IOC 容器。 我们在参数列表中指定我们需要一个视图类,Masonite 将为我们注入它。

现在我们不会关注整个控制器,而只会关注我们需要关心的部分。 ... 表示中间有我们不需要关心的代码:

app/controllers/BlogController.py

from masonite.view import View
# ...
def show(self, view: View):
    return view.render('blog')

注意这里我们“类型提示”了 View 类。 这就是 Masonite 所说的「自动解析依赖注入」,如果这对你现在没有意义,请不要担心。 你读的越多,你就会明白的越多。

创建视图

你现在会注意到我们正在返回 blog 视图,但它还不存在。

所有视图都在 templates 目录中。 我们可以创建一个名为 templates/blog.html 的新文件。

我们可以在这个文件中放一些文本,比如:

templates/blog.html

This is a blog

让我们第一次运行迁移:

terminal

$ python craft migrate

然后运行服务器

terminal

$ python craft serve

并打开http://localhost:8000/blog。 你将在浏览器中看到「这是一个博客」。

身份校验

很多时候,大多数程序都需要某些特殊的身份验证方式 Masonite 自带了一个craft命令,来帮您搭建一个身份校验系统框架. 通常情况下,建议您应该在全新的Masonite下使用,因为它会自动帮您创建新的控制器、路由器和视图.

对于我们的博客来说,我们需要创建某种形式的注册方式,以至于允许新的用户在我们的博客上发言。 我们可以通过运行 craft 命令来创建一个身份验证系统:

terminal

$ python craft auth

运行后我们会受到一条成功提示,表明已经创建了新的资源. 你可以查看先您的控制器文件夹,在里面您应该能看到一些新的、应该注册的控制器

然后你就可以将身份校验的路由添加到你的项目中

from masonite.authentication import Auth

ROUTES = [
    Route.get('/', 'WelcomeController@show').name('welcome'),

    # Blog Routes
    Route.get('/blog', 'BlogController@show')
]

ROUTES += Auth.routes()

稍后,我们就能看到为我们创建了什么样的内容

Database Setup

为了让这些用户成功注册, 我们还需要一个数据库。 默认的,Masonite 使用的是SQLite,如果你想使用其他的数据库,您能直接修改 .env文件中开头为DB_的选项,如果是要运行 MySQL 或 Postgres数据库服务,您需要确保已经运行这些服务

重新运行我们之前已经运行过的迁移命令,即:

terminal

$ python craft migrate

如果您要使用 MySQL作为您的数据库,请打开项目根目录中的.env文件,并将DB_DATABASE更改为mysql。当然,也能修改成其他你所喜欢的

terminal

.env

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=masonite
DB_USERNAME=root
DB_PASSWORD=

执行迁移

配置完成数据库连接信息后, 就可以进行数据库迁移. 在 Masonite 中提供一个基础的用户迁移模型。默认配置能够满足大多数情况,你可以修改迁移模型中的配置或者在以后再对迁移模型进行修改。

$ python craft migrate

该操作会创建一个 users 表和 migrations,在 migrations 表中记录着我们所有的迁移记录。

创建用户

现在我们已经迁移完成,下面开始创建第一个用户,通过 craft auth 命令,可以创建新的模板和控制器。

下面我们开始运行服务:

$ python craft serve

访问 localhost:8000/register 并完成注册,你可以使用你喜欢的用户名和邮箱进行注册,本教程使用下面信息进行注册:

Username: demo
Email: demo@email.com
Password: password!!11AA

迁移

我们已经了解了迁移的基本流程,下面我们来创建一个新的数据迁移。

在我们的应用中已经完成 users 的迁移,下面我们来创建一个 posts 模型迁移,用来存储我们的文章信息。

我们的帖子表应该有一些明显的列,我们将在本教程部分进行简化。

Craft 命令

我们可以使用 craft 命令创建数据迁移。详情查看数据库迁移文档,此处我们将简化此命令并稍作解释:

terminal

$ python craft migration create_posts_table --create posts

该命令创建了一个数据库迁移文件,我们可以用它来新建 posts 表格。按照命名规范,表格名应该是复数(而模型名称应该为单数)。

这将会在 databases/migrations 目录新建一个迁移文件。打开该文件,会看到第六行开始其内容如下:

databases/migrations/20YY_MM_DD_ABCDEF_create_posts_table.py

def up(self):
    """
    Run the migrations.
    """
    with self.schema.create('posts') as table:
        table.increments('id')
        table.timestamps()

接下来,我们将添加 title、author 和 body 字段到 posts 表格中。

databases/migrations/2018_01_09_043202_create_posts_table.py

def up(self):
    """
    Run the migrations.
    """
    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()

提示:这已经相当直白易懂了。如果你想了解跟多,请查阅数据库迁移文档。

现在,我们就可以运行迁移,创建 post 表了

terminal

$ python craft migrate

模型

既然已经完成了表格迁移,有了 posts 表,那我们就来为其创建一个模型吧。

Masonite 中的模型与其他 Python 框架稍有一点不同。Masonite 使用的是Active Record ORM。在 Masonite 中模型和迁移是分离的。无论数据库表内部字段如何调整,模型都能适用表格。

创建模型

使用 craft 命令创建模型:

terminal

$ python craft model Post

注意,模型名称使用单数。默认情况下,Masonite ORM 会假定表格的名称为模型名称的复数形式,此例中类名的Post复数为posts。稍后,我们将稍微解释一下如何指定表格名称。

当前创建的这一模型在 app/models/Post.py 中,其代码如下:

app/models/Post.py

"""Post Model."""
from masoniteorm.models import Model

class Post(Model):
    pass

很简单吧?如前所述,我们可以不必操作模型。即便我们创建或者修改迁移,模型仍然适用表格。

表名

重申一下,模型中使用的表名,是模型名称的复数形式。不过,如果你使用了不同的表名。比如,表名使用的是 "user_posts" 而非 "posts" 时,我们可以明确指定表名:

app/Post.py

"""Post Model."""
from masoniteorm.models import Model

class Post(Model):
    __table__ = 'user_posts'

批量赋值

默认情况下, Masonite ORM 出于安全考虑对批量赋值启用了保护,因此,我们需要另外设置哪些字段是可填充的(fillable),这样我们才可以将字段名传入 createupdate 方法中。

app/Post.py

"""A Post Database Model."""
from masoniteorm.models import Model

class Post(Model):
    __fillable__ = ['title', 'author_id', 'body']

表关联

此处的表关联相当直接易懂。我们在数据迁移(migration)文件中,添加了一个外键。我们可以在模型中像这样创建关联:

app/models/Post.py

"""Post Model."""
from masoniteorm.models import Model
from masoniteorm.relationships import belongs_to

class Post(Model):
    __fillable__ = ['title', 'author_id', 'body']

    @belongs_to('author_id', 'id')
    def author(self):
        from app.models.User import User
        return User

由于Masonite 模型的实现方式,有一些模型会相互依赖。因此最好像我们上面所做的那样,在关联内部进行引入,以避免可能的循环引入。

提示:此处不会涉及不同类型关联的详情,需要了解更多信息请查阅Masonite ORM Relationships文档

设计博客

我们来准备一些 HTML ,借此了解一下视图(view)是如何运作的。在这一部分中,我们会准备一个很基础的模板,这样才不至于被太多的HTML耽搁,同时又能了解足够多的基础。

既然模型和数据库迁移都已准备好,后台的其他东西也都已经有了,现在我们只需创建布局,然后就可以开始创建和更新博客文章了。

同时,我们也需要在创建模板前检查用户是否已经登录。

用于创建记录的模板

添加记录的URL为 /blog/create ,其中会有一个简单的表单用于添加博客文章

templates/blog.html

<form action="/blog/create" method="POST">
    {{ csrf_field }}

    <input type="name" name="title">
    <textarea name="body"></textarea>
</form>

注意此处 <form> 标签之下有一个 {{ csrf_field }}。Masonite 自带 CSRF 保护,因此我们需要添加一个隐藏的字段带上 CSRF token。

现在,我们需要确保用户已经登录,因此我们可以对模板稍加修改:

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 模板。如果你不了解这一模板,请查看相关文档

静态文件

为简化起见,我们不会采用像Bootstrap这样的框架来编写博客样式。不过,了解像CSS这样的静态文件,是如何在 Masonite 中使用,仍然很重要。接下来,我们一起来看看如何添加CSS文件到博客当中吧。

首先,转到 storage/static/ 目录并新建一个 blog.css 文件,在其中定义你的样式。此处我们将让页面变灰。

storage/static/blog.css

html {
    background-color: #ddd;
}

现在我们可以将其添加到在模板头部:

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 文件也完全一样:

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 Route
# ...
ROUTES = [
    # ...
    Route.post('/blog/create', 'BlogController@store')
]

然后再控制器中添加 store 方法:

app/controllers/BlogController.py

...
def show(self, view: View):
    return view.render('blog')

# 新增store方法
def store(self):
    pass

现在注意以上表单,我们会收到两个表单输入数据: title 和 body。这里引入 Post 模型,然后使用输入数据创建新的 post 文章。

app/controllers/BlogController.py

from app.models.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) 。这是一个需要掌握的重要的概念,所以请阅读文档做进一步了解。

同时请注意,我们使用了 input() 方法。Masonite 不歧视不同的请求方法,因此从 GETPOST 请求获得的输入,在使用 input 方法时,是一样的。

使用 craft serve 再次启动服务,然后转到 http://localhost:8000/blog 并创建一个新文章。这会使用 POST 方法提交到 /blog/create 路由,然后我们就会看到"post created"。

展示文章列表

接下来,我们继续看看怎样展示刚刚创建的博客文章。既然我们更愿意使用框架,这部分我们将创建两个模板,用来展示所有文章和单篇文章。

创建模板

我们将创造两个模板。

  • templates/posts.html
  • templates/single.html

我们先来展示文章列表

创建控制器

接下来我们将为文章创建一个控制器并且从 BlogController 中分离出来。

terminal

$ python craft controller Post

很好,现在在我们 show 方法中,我们可以展示所有文章了。接下来我们将创建一个 single 方法,用来显示指定文章。

Show 方法

接下来,我们来实现 show 方法,并返回所有文章的视图:

app/controllers/PostController.py

from app.models.Post import Post

...

def show(self, view: View):
    posts = Post.all()

    return view.render('posts', {'posts': posts})

文章(Posts)路由

我们需要为此方法添加一个路由:

routes/web.py

Route.get('/posts', 'PostController@show')

文章列表(Posts)视图

视图可以非常简单:

<!-- templates/posts.html -->
@for post in posts
    {{ post.title }}
    <br>
    {{ post.body }}
    <hr>
@endfor

启动服务,然后打开 http://localhost:8000/posts 路由。你就会看到文章列表的基本展示。如果你只看到一篇,你可以到 http://localhost:8000/blog 添加更多文章。

显示作者

之前我们添加 author 关联。Masonite ORM 可以获取这一关联,并从中读取属性,将作者名字显示出来:

templates/posts.html

@for post in posts
    {{ post.title }} by {{ post.author.name }}
    <br>
    {{ post.body }}
    <hr>
@endfor

我们再来重复一遍这一过程,稍微调整一下流程。

单篇文章路由

接下来,我们将要显示单篇文章。我们需为此添加路由:

routes/web.py

Route.get('/post/@id', 'PostController@single')

注意此处我们有一个 @id 字符串。我们可以在接下来的控制器中,用它来抓取URL中相应位置的参数。

Single 方法

我们来新建一个 single 方法,用来显示单篇文章。

app/controllers/PostController.py

from app.models.Post import Post
from masonite.request import Request
from masonite.views 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 对其进行了设置。

提示:在真实的应用中,我们可能会在路由中使用 @slug,然后通过 request().param('slug') 获取。

单篇文章视图

我们只需显示一篇文章,因此我们且用一个简单的视图:

templates/single.html

{{ post.title }}
<br>
{{ post.body }}
<hr>

运行服务器,然后跳到 http://localhost:8000/post/1http://localhost:8000/post/2 两个路由,观察它们有何不同。

更新及删除文章

至此,前面用过所有这些业务逻辑已经足以让我们更进一步,因此接下来我们将快速完成文章的更新和删除操作。

Update 控制器方法

接下来,我们在 PostController 中创建一个 update 方法:

app/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'

由于我们对控制器更满意,我们可以继续制作两个。我们制作了一个视图,该视图显示了一个更新帖子的表单,然后是一个实际使用数据库更新帖子的视图。

创建视图

  • templates/update.html

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>

创建路由:

请记住,我们创建了 2 个控制器方法,所以让我们在这里将它们附加到一个路由:

routes/web.py

Route.get('/post/@id/update', 'PostController@update'),
Route.post('/post/@id/update', 'PostController@store'),

应该是这样!我们现在可以更新我们的帖子。

删除方法

让我们扩展一下并创建一个删除方法。

app/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

Route.get('/post/@id/delete', 'PostController@delete'),

请注意,我们在这里使用了GET路由,使用POST方法会更好,但为简单起见,假设您现在可以创建一个。我们将只添加一个链接到我们的更新方法,这将删除帖子。

更新模板

我们可以在更新模板中直接添加一个删除链接:

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>

太棒了!您现在拥有一个可用于创建、查看、更新和删除帖子的博客!继续创造惊人的东西!

本文章首发在 LearnKu.com 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://learnku.com/docs/masonite/4.0/pr...

译文地址:https://learnku.com/docs/masonite/4.0/pr...

上一篇 下一篇
贡献者:9
讨论数量: 0
发起讨论 只看当前版本


暂无话题~