视图
视图
视图
介绍
视图包含您的应用程序要呈现给用户的所有 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 和行语句定义。它使您可以结构化模板并减少重复代码。
子模板中定义的块将被传递到父模板。
本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。