视图

未匹配的标注
本文档最新版为 4.0,旧版本可能放弃维护,推荐阅读最新版!

视图

视图

介绍

视图包含您的应用程序要呈现给用户的所有 HTML 。与 Django 不同,Masonite 中的视图是您的HTML模板。所有视图都位于 resources / templates 目录中。

所有视图都是用 Jinja2 渲染的,因此我们可以使用所有 Jinja2 的语法。视图示例如下所示:

resources/templates/helloworld.html

<html>
  <body>
    <h1> Hello {{ 'world' }}</h1>
  </body>
</html>

创建视图

由于所有视图都位于 resources/templates 目录中,因此我们可以在这个目录里手动创建所有视图,或使用我们的 craft 命令工具。要生成视图文件,只需运行:

$ craft view hello

这样就创建了一个视图文件 resources/templates/hello.html

加载视图

View 类已加载到容器中,因此我们可以在控制器方法中使用它,如下所示:

app/http/controllers/YourController.py

from masonite.view import View

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

这与使用辅助函数没啥差别。如果你想让你的代码清晰明了,你可以使用这种方式。

如果你觉得这种方式很奇怪或者不确定 Masonite 如何使用容器,请阅读 服务容器 相关内容。

全局视图

某些视图可能不在 resources/templates 目录,甚至可能在第三方程序包里。我们可以通过使用 / 来定位视图文件。

举个例子,我们安装一个包:

$ pip install package-dashboard

然后返回它的一个视图:

app/http/controllers/YourController.py

def show(self, view: View):
    return view.render('/package/views/dashboard')

这样将会在 dashboard.views 包找到 dashboard.html 文件并返回。你还可以跟以前一样传递数据进去。

注意

这里一定要注意,如果您要构建一个与 Masonite 集成的第三方程序包,需要将所有的 .html 文件放在 Python 程序包中,而不能放在某个模块里。例如,您应该将 .html 文件放在如下的文件结构中:

package/
  views/
    __init__.py
    index.html
    dashboard.html
setup.py
MANIFEST.in
...

并确保有 __init__.py 文件。Jinja2 规定所有模板文件都要放在包中。

按照如下方式访问全局视图:

app/http/controllers/YourController.py

def show(self, view: View):
    return view.render('/package/dashboard')

这将按照绝对路径导入到您的 Masonite 项目。 文件结构如下:

app/
config/
databases/
...
package/
  dashboard.html

或者在完全独立的第三方模块中找到包。所以,如果要为 Masonite 构建包,请记住将模板文件放在何处。

传递数据

大多数情况下我们都需要将数据传递给视图。数据是通过 包含键值对的字典进行传递的。参考如下:

app/http/controllers/YourController.py

def show(self, view: View, request: Request):
    return view.render('dashboard', {'id': request.param('id')})

请记住,通过诸如 Request 之类的参数传递给控制器方法,我们可以从 IOC 容器中获取对象。阅读 服务容器 了解相关知识。

这将向视图传递一个名为 id 的变量,然后展示出来:
resources/templates/dashboard.html

<html>
  <body>
    <h1> {{ id }} </h1>
  </body>
</html>

视图语法

视图使用 Jinja2 作为模板引擎. 您可以阅读 Jinja2 官方文档.

Masonite默认情况下启用了 Jinja2 行语法,这使您可以按常规方式编写语法:

{% extends 'nav/base.html' %}

{% block content %}
    {% for element in variables %}
        {{ element }}
    {% endfor %}

    {% if some_variable %}
        {{ some_variable }}
    {% endif %}

{% endblock %}

或使用带有 @ 字符的行语法:

@extends 'nav/base.html'

@block content
    @for element in variables
        {{ element }}
    @endfor

    @if some_variable
        {{ some_variable }}
    @endif

@endblock

具体使用哪种写法取决于您。但是请记住,行语法必须独立占一行,前面和后边都不能有内容。

添加环境

这部分需要您了解 服务提供者 以及 服务容器 是如何工作的。务必阅读这些文档。

您还可以将 Jinja2 环境添加到容器中,以便在视图中使用。这通常是针对第三方程序包(例如 Masonite Dashboard )完成的。您可以通过启动方法在服务提供者中扩展视图。前提是确保服务提供者的 wsgi 属性设置为 False 。这样,特定的服务提供者就不会在每个请求上添加环境。

from masonite.view import View

wsgi = False

...

def boot(self, view: View):
    view.add_environment('dashboard/templates')

默认情况下,将使用 PackageLoader Jinja2 加载器添加环境,但是您可以明确指定要使用的加载器:

from jinja2 import FileSystemLoader
from masonite.view import View
...
wsgi = False

...

def boot(self, view: View):
    view.add_environment('dashboard/templates', loader=FileSystemLoader)

PackageLoader 的默认加载器在大多数情况下都可以使用,但是如果不适用于您的项目,您可以更改 Jinja2 加载器类型。

使用 . 符号

如果使用 / 看起来不太整洁,则还可以选择使用点:

def show(self, view: View):
    view.render('dashboard.user.show')

如果要使用全局视图,则仍需要使用 / 放在第一个字符:

def show(self, view: View):
    view.render('/dashboard.user.show')

辅助方法

在视图里有很多内置的辅助方法。下面是辅助方法的详细列表:

Request

您可以获取到请求类:

<p> Path: {{ request().path }} </p>

Static

您可以获取到静态资源的位置:
如果您有如下的配置文件:

config/storage.py

....
's3': {
  's3_client': 'sIS8shn...'
  ...
  'location': 'https://s3.us-east-2.amazonaws.com/bucket'
  },
....
...
<img src="{{ static('s3', 'profile.jpg') }}" alt="profile">
...

这将会渲染出:

<img src="https://s3.us-east-2.amazonaws.com/bucket/profile.jpg" alt="profile">

CSRF 字段

您可以创建一个隐藏的 CSRF 令牌字段和表单一起使用:

<form action="/some/url" method="POST">
    {{ csrf_field }}
    <input ..>
</form>

CSRF 令牌

您可以只获取生成的令牌。这对于需要将 CSRF 令牌传递到后端以进行AJAX调用很有用。

<p> Token: {{ csrf_token }} </p>

当前用户

您还可以获取当前经过身份验证的用户。这与执行 request.user() 相同。

<p> User: {{ auth().email }} </p>

请求方法

在表单中,由于html的特性,通常只能使用 GET 或 POST 。使用 Masonite ,您可以使用辅助函数通过 PUT 或 DELETE 提交表单。

<form action="/some/url" method="POST">
    {{ request_method('PUT') }}
    <input ..>
</form>

此表单将作为PUT请求提交。

路由方法

您可以使用以下方法通过路由名称获取路由:

<form action="{{ route('route.name') }}" method="POST">
    ..
</form>

如果您的路由包含变量,则可以提供字典作为第二个参数。

<form action="{{ route('route.name', {'id': 1}) }}" method="POST">
    ..
</form>

或者列表:

<form action="{{ route('route.name', [1]) }}" method="POST">
    ..
</form>

另一个很酷的功能是,如果当前路由已经包含正确的字典,那么您不必传递第二个参数。例如,如果您有2条路线:

Get('/dashboard/@id', 'Controller@show').name('dashboard.show'),
Get('/dashhboard/@id/users', 'Controller@users').name('dashhboard.users')

如果要访问这2条路由,则 @id 参数将存储在用户对象上。因此,不要这样做:

<form action="{{ route('dashboard.users', {'id': 1}) }}" method="POST">
    ..
</form>

您可以完全省略它,因为 id 键已经存储在请求对象中:

<form action="{{ route('dashboard.users') }}" method="POST">
    ..
</form>

返回函数

这对于重定向回到上一页很有用。如果使用这个辅助函数,则request.back() 方法将转到此。提交表单如果发生错误,通常最好使用它返回页面:

<form action="/some/url" method="POST">
    {{ back(request().path) }}
</form>

现在,提交表单后,您想让用户跳转回去,只需在控制器中执行以下操作:

def show(self, request: Request):
    # 某些验证失败
    return request.back()

Old

request.back() 方法也会将当前输入刷新到会话中,以便您在模板中可以获取它们。您可以使用 old() 方法获取这些值:

<form>
  <input type="text" name="email" value="{{ old('email') }}">
  ...
</form>

Session

您可以访问会话数据:

<p> Error: {{ session().get('error') }} </p>

学习更多 会话 知识。

Sign

您可以使用您的密钥来签名:

<p> Signed: {{ sign('token') }} </p>

Unsign

您可以取消签名您签名过的串:

<p> Signed: {{ unsign('signed_token') }} </p>

Encrypt

同 sign

Decrypt

同 unsign

Config

这个方法可以让您在模板中轻松获取到配置值:

<h2> App Name: {{ config('application.name') }}</h2>

Optional

允许您从可能为None或不为None的对象中获取值。比如下面的用法:

{% if auth() and auth().name == 'Joe' %}
    <p>Hello!</p>
{% endif %}

您就可以使用这个辅助方法来代替:

{% if optional(auth()).name == 'Joe' %}
    <p>Hello!</p>
{% endif %}

DD

这个就是您在控制器中使用的 dd() 方法。

Hidden

您可以使用这个方法 hidden 快速隐藏一个字段:

<form action="/" method="POST">
    {{ hidden('secret' name='secret-value') }}
</form>

Exists

检查模板是否存在:

{% if exists('auth/base') %}
    {% extends 'auth/base.html' %}
{% else %}
    {% extends 'base.html' %}
{% endif %}

Cookie

获取cookie:

<h2> Token: {{ cookie('token') }}</h2>

Url

获取指向某个地址的链接:

<form action="{{ url('/about', full=True) }}" method="POST">

</form>

译者在测试的过程中发现 url() 参数必须是路由的名称,否则报错。

Jinja2

以下是 Masonite 用于构建视图的 Jinja2 语法的一些示例。

Line Statements

要注意,Jinja2 语句可以用行语句重写,并且在 Masonite 中“首选”行语句。与 Jinja2 相比,行语句对整行进行评估,因此命名行语句。

Jinja2语法如下所示:

{% if expression %}
    <p>do something</p>
{% endif %}

可以使用行语句语法将其重写为:

@if expression
    <p>do something</p>
@endif

值得注意的是,就是因为这些都是行语句,意味着在这一行里不能有其他的操作。例如您不能这么做:

<form action="@if expression: 'something' @endif">

</form>

但是您可以使用常规格式来实现:

<form action="{% if expression %} 'something' {% endif %}">

</form>

具体使用哪种语法取决于您。

变量

您可以使用 {{}} 字符显示变量:

<p>
    {{ variable }}
</p>
<p>
    {{ 'hello world' }}
</p>

If 语句

if 语句类似于 python语法,但需要一个 endif !
行语句:

@if expression
    <p>do something</p>
@elif expression
    <p>do something else</p>
@else
    <p>above all are false</p>
@endif

使用 Jinja2 语法:

{% if expression %}
    <p>do something</p>
{% elif %}
    <p>do something else</p>
{% else %}
    <p>above all are false</p>
{% endif %}

For 循环

For 循环类似于常规 python 语法。

行语句:

@for item in items
    <p>{{ item }}</p>
@endfor

使用 Jinja2 语法:

{% for item in items %}
    <p>{{ item }}</p>
{% endfor %}

包含语句

包含语句在包含其他模板的时候非常有用。

行语句:

@include 'components/errors.html'

<form action="/">

</form>

使用 Jinja2 语法:

{% include 'components/errors.html' %}

<form action="/">

</form>

您可以在任何有重复代码的地方进行拆分,并将其放入包含模板中。这些模板将有权访问当前模板中的所有变量。

Extends

这对于让子模板扩展父模板很有用。每个模板只能有1个扩展:

行语句:

@extends 'components/base.html'

@block content
    <p> read below to find out what a block is </p>
@endblock

使用 Jinja2 语法:

{% extends 'components/base.html' %}

{% block content %}
    <p> read below to find out what a block is </p>
{% endblock %}

Blocks

块是父模板中充当占位符的代码片段。这些仅与上面的 extends 一起使用时才有用。 “ base.html” 模板是父模板,并包含在子模板“ blocks.html”中定义的块。

行语句:

<!-- components/base.html -->
<html>
    <head>
        @block css 
        <!-- -子模板中定义的名为“ css” 的块将插入此处 -->
        @endblock
    </head>

<body>
    <div class="container">
        @block content
        <!-- -子模板中定义的名为“ content”的块将插入此处 -->
        @endblock
    </div>

@block js
<!-- -子模板中定义的名为“ js”的块将插入此处 -->
@endblock

</body>
</html>
<!-- components/blocks.html -->
@extends 'components/base.html'

@block css
    <link rel=".." ..>
@endblock

@block content
    <p> This is content </p>
@endblock

@block js
    <script src=".." />
@endblock

使用 Jinja2 语法:

<!-- components/base.html -->
<html>
    <head>
        {% block css %} 
        <!-- 子模板中定义的名为“ css”的块将插入此处 -->
        {% endblock %}
    </head>

<body>
    <div class="container">
        {% block content %} 
        <!-- 子模板中定义的名为“ content”的块将插入此处-->
        {% endblock %}
    </div>

{% block js %}
<!-- -子模板中定义的名为“ js”的块将插入此处 -->
{% endblock %}

</body>
</html>
<!-- components/blocks.html -->
{% extends 'components/base.html' %}

{% block css %}
    <link rel=".." ..>
{% endblock %}

{% block content %}
    <p> This is content </p>
{% endblock %}

{% block js %}
    <script src=".." />
{% endblock %}

如上,块是最基本的,可以用 Jinja2 和行语句定义。它使您可以结构化模板并减少重复代码。

子模板中定义的块将被传递到父模板。

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

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

原文地址:https://learnku.com/docs/masonite/2.3/th...

译文地址:https://learnku.com/docs/masonite/2.3/th...

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


暂无话题~