Python Flask Web框架教程 2 模板

原文

在完成第1章之后,你将拥有一个具有以下文件结构的可正常运行且简单的Web应用程序:

microblog\
  venv\
  app\
    __init__.py
    routes.py
  microblog.py

要运行该应用程序,请在终端会话中设置FLASK_APP = microblog.py,然后执行flask run。 这将使用该应用程序启动Web服务器,你可以通过在Web浏览器的地址栏中键入http://localhost:5000/ URL来打开该服务器。

在本章中,你将继续使用同一应用程序,特别是,你将学习如何生成具有复杂结构和许多动态组件的更精致的网页。 如果到目前为止尚不清楚有关应用程序或开发工作流程的任何内容,请在继续之前再次阅读第1章

本章的GitHub链接是:浏览压缩差异

What Are Templates?

我希望我的微博应用程序的首页具有欢迎用户的标题。 目前,我将忽略以下事实:该应用程序还没有用户概念,因为这将在以后出现。 相反,我将使用模拟用户,该用户将作为Python字典实现,如下所示:

user = {'username': 'Miguel'}

创建模拟对象是一种有用的技术,它使你可以专注于应用程序的一部分,而不必担心系统中尚不存在的其他部分。 我想设计应用程序的主页,也不希望没有适当的用户系统来分散我的注意力,所以我只是组成了一个用户对象,以便继续前进。

应用程序中的view函数返回一个简单的字符串。 我现在想做的是将返回的字符串扩展为完整的HTML页面,也许是这样的:

#app/routes.py: Return complete HTML page from view function

from app import app

@app.route('/')
@app.route('/index')
def index():
    user = {'username': 'Miguel'}
    return '''
<html>
    <head>
        <title>Home Page - Microblog</title>
    </head>
    <body>
        <h1>Hello, ''' + user['username'] + '''!</h1>
    </body>
</html>'''

如果你不熟悉HTML,建议你阅读Wikipedia上的HTML标记以作简要介绍。

如上所述更新视图功能,并尝试在浏览器中查看应用程序的外观。

我希望你同意我的观点,以上将HTML传输到浏览器的解决方案不是很好。考虑一下当我收到来自用户的博客文章时,此视图功能中的代码将变得多么复杂,并且这些博客文章将不断变化。该应用程序还将具有更多的视图功能,这些视图功能将与其他URL关联,因此想象一下,如果有一天我决定更改此应用程序的布局,并且必须在每个视图功能中更新HTML。显然,这不是随应用程序的增长而扩展的选项。

如果你可以将应用程序的逻辑与网页的布局或表示形式分开,那么事情就会井井有条,不是吗?在用Python编写应用程序逻辑时,你甚至可以雇用一名Web设计人员来创建一个杀手级网站。

模板有助于实现表示和业务逻辑之间的分离。在Flask中,模板被写为单独的文件,存储在应用程序包内的templates文件夹中。因此,在确保你位于microblog目录中之后,创建用于存储模板的目录:

(venv) $ mkdir app/templates

在下面,你可以看到你的第一个模板,其功能与上面的index()视图函数返回的HTML页面相似。 将此文件写入app/templates/index.html中:

<!--app/templates/index.html: Main page template/-->

<html>
    <head>
        <title>{{ title }} - Microblog</title>
    </head>
    <body>
        <h1>Hello, {{ user.username }}!</h1>
    </body>
</html>

这是一个非常标准的HTML页面。 此页面上唯一有趣的事情是,在{{...}}部分中包含了几个用于动态内容的占位符。 这些占位符代表页面的可变部分,只有在运行时才知道。

现在,页面的显示已被卸载到HTML模板,可以简化视图功能:

#app/routes.py: Use render\_template() function

from flask import render_template
from app import app

@app.route('/')
@app.route('/index')
def index():
    user = {'username': 'Miguel'}
    return render_template('index.html', title='Home', user=user)

这样看起来好多了,对吗? 尝试使用此新版本的应用程序以查看模板的工作方式。 在浏览器中加载页面后,你可能需要查看源HTML并将其与原始模板进行比较。

将模板转换为完整的HTML页面的操作称为渲染(rendering)。 为了渲染模板,我必须导入Flask框架随附的称为render_template()的函数。 此函数采用模板文件名和模板参数的变量列表,并返回相同的模板,但其中的所有占位符均替换为实际值。

render_template()函数将调用Flask框架随附的Jinja2模板引擎。 Jinja2用相应的值替换{{...}}块,这些值由render_template()调用中提供的参数给出。

Conditional Statements

你已经看到Jinja2如何在渲染过程中用实际值替换占位符,但这只是Jinja2在模板文件中支持的许多强大操作之一。 例如,模板还支持在{%...%}块内给出的控制语句。 下一个index.html模板版本添加了一条条件语句:

<!--app/templates/index.html: Conditional statement in template-->

<html>
    <head>
        {% if title %}
        <title>{{ title }} - Microblog</title>
        {% else %}
        <title>Welcome to Microblog!</title>
        {% endif %}
    </head>
    <body>
        <h1>Hello, {{ user.username }}!</h1>
    </body>
</html>

现在,模板更加智能。 如果view函数忘记传递title占位符变量的值,则模板将显示默认标题,而不是显示空标题。 你可以通过在视图函数的render_template()调用中删除title参数来尝试此条件的工作方式。

Loops

登录的用户可能希望在主页中查看已连接用户的最新帖子,因此我现在要做的就是扩展应用程序以支持该操作。

再一次,我将依靠方便的假对象技巧来创建一些用户和一些帖子来显示:

#app/routes.py: Fake posts in view function

from flask import render_template
from app import app

@app.route('/')
@app.route('/index')
def index():
    user = {'username': 'Miguel'}
    posts = [
        {
            'author': {'username': 'John'},
            'body': 'Beautiful day in Portland!'
        },
        {
            'author': {'username': 'Susan'},
            'body': 'The Avengers movie was so cool!'
        }
    ]
    return render_template('index.html', title='Home', user=user, posts=posts)

为了表示用户帖子,我使用了一个列表,其中每个元素都是具有authorbody字段的字典。 当我真正实现用户和博客文章时,我将尝试尽可能保留这些字段名称,以便使用这些假对象设计和测试主页模板的所有工作将继续进行。 在介绍真实用户和帖子时有效。

在模板方面,我必须解决一个新问题。 帖子列表可以包含任意数量的元素,由查看功能决定页面中将显示多少帖子。 该模板不能对有多少个帖子做出任何假设,因此需要准备好呈现与视图以通用方式发送的一样多的帖子。

对于此类问题,Jinja2提供了for控件结构:

<!--app/templates/index.html: for-loop in template-->

<html>
    <head>
        {% if title %}
        <title>{{ title }} - Microblog</title>
        {% else %}
        <title>Welcome to Microblog</title>
        {% endif %}
    </head>
    <body>
        <h1>Hi, {{ user.username }}!</h1>
        {% for post in posts %}
        <div><p>{{ post.author.username }} says: <b>{{ post.body }}</b></p></div>
        {% endfor %}
    </body>
</html>

简单吧? 请尝试使用该新版本的应用程序,并确保将更多内容添加到帖子列表中,以查看模板如何适应并始终呈现视图功能发送的所有帖子。

Template Inheritance

如今,大多数Web应用程序在页面顶部都有一个导航栏,其中包含一些常用链接,例如用于编辑个人资料,登录,注销等的链接。我可以轻松地将导航栏添加到index.html。 带有更多HTML的模板,但是随着应用程序的增长,我将在其他页面中需要相同的导航栏。 我并不是很想在许多HTML模板中维护导航栏的多个副本,如果可能的话,最好不要重复自己的做法。

Jinja2具有专门解决此问题的模板继承功能。 本质上,你可以做的是将页面布局中所有模板共有的部分移动到基本模板,所有其他模板都从该基本模板中派生。

因此,我现在要做的是定义一个名为base.html的基本模板,该模板包括一个简单的导航栏以及我之前实现的标题逻辑。 你需要在文件app/templates/base.html中编写以下模板:

<!--app/templates/base.html: Base template with navigation bar-->

<html>
    <head>
      {% if title %}
      <title>{{ title }} - Microblog</title>
      {% else %}
      <title>Welcome to Microblog</title>
      {% endif %}
    </head>
    <body>
        <div>Microblog: <a href="/index">Home</a></div>
        <hr>
        {% block content %}{% endblock %}
    </body>
</html>

在此模板中,我使用了block控制语句来定义派生模板可插入自身的位置。 块具有唯一的名称,派生的模板在提供其内容时可以引用这些名称。

有了基本模板之后,我现在可以通过使其继承自base.html来简化index.html

<!--app/templates/index.html: Inherit from base template-->

{% extends "base.html" %}

{% block content %}
    <h1>Hi, {{ user.username }}!</h1>
    {% for post in posts %}
    <div><p>{{ post.author.username }} says: <b>{{ post.body }}</b></p></div>
    {% endfor %}
{% endblock %}

由于base.html模板现在将处理常规的页面结构,因此我从index.html中删除了所有这些元素,仅保留了内容部分。 extend语句在两个模板之间建立继承链接,因此Jinja2知道当要求呈现index.html时,需要将其嵌入base.html中。 这两个模板具有匹配的带有名称contentblock语句,这就是Jinja2知道如何将两个模板组合为一个的方式。 现在,如果需要为该应用程序创建其他页面,则可以将它们创建为来自同一base.html模板的派生模板,这就是我可以使应用程序的所有页面共享相同外观的方式,而无需重复。

原文地址:https://blog.csdn.net/sunny_98_98/article/details/112846267

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Jinja2:是Python的Web项目中被广泛应用的模板引擎,是由Python实现的模板语言,Jinja2 的作者也是 Flask 的作者。他的设计思想来源于Django的模板引擎,并扩展了其语法和一系列强大的功能,其是Flask内置的模板语言。
Fullcalendar日历使用,包括视图选择、事件插入、编辑事件、事件状态更改、事件添加和删除、事件拖动调整,自定义头部,加入el-popover显示图片、图片预览、添加附件链接等,支持手机显示。
监听QQ消息并不需要我们写代码,因为市面上已经有很多开源QQ机器人框架,在这里我们使用go-cqhttp官方文档:go-cqhttp如果您感兴趣的话,可以阅读一下官方文档,如果不想看,直接看我的文章即可。
【Flask框架】—— 视图和URL总结
python+web+flask轻量级框架的实战小项目。登录功能,后续功能可自行丰富。
有了这个就可以配置可信IP,关键是不需要企业认证,个人信息就可以做。
本专栏是对Flask官方文档中个人博客搭建进行的归纳总结,与官方文档结合事半功倍。 本人经验,学习一门语言或框架时,请首先阅读官方文档。学习完毕后,再看其他相关文章(如本系列文章),才是正确的学习道路。
本专栏是对Flask官方文档中个人博客搭建进行的归纳总结,与官方文档结合事半功倍。基础薄弱的同学请戳Flask官方文档教程 本人经验,学习一门语言或框架时,请首先阅读官方文档。学习完毕后,再看其他相关文章(如本系列文章),才是正确的学习道路。 如果python都完全不熟悉,一定不要着急学习框架,请首先学习python官方文档,一步一个脚印。要不然从入门到放弃是大概率事件。 Python 官方文档教程
快到年末了 相信大家都在忙着处理年末数据 刚好有一个是对超市的商品库存进行分析的学员案例 真的非常简单~
一个简易的问答系统就这样完成了,当然,这个项目还可以进一步完善,比如 将数据存入Elasticsearch,通过它先进行初步的检索,然后再通过这个系统,当然我们也可以用其他的架构实现。如果你对这系统还有其他的疑问,也可以再下面进行留言!!!
#模版继承和页面之间的调用@app.route(&quot;/bl&quot;)def bl(): return render_template(&quot;file_2.html&quot;)主ht
#form表达提交@app.route(&quot;/data&quot;,methods=[&#39;GET&#39;,&#39;POST&#39;]) #methods 让当前路由支持GET 和
#form表达提交@app.route(&quot;/data&quot;,methods=[&#39;GET&#39;,&#39;POST&#39;]) #methods 让当前路由支持GET 和
#session 使用app.secret_key = &quot;dsada12212132dsad1232113&quot;app.config[&#39;PERMANENT_SESSION_LI
#文件上传@app.route(&quot;/file&quot;,methods=[&#39;GET&#39;,&#39;POST&#39;])def file(): if request.meth
#跳转操作:redirect@app.route(&quot;/red&quot;)def red(): return redirect(&quot;/login&quot;)
#session 使用app.secret_key = &quot;dsada12212132dsad1232113&quot;app.config[&#39;PERMANENT_SESSION_LI
@app.route(&quot;/req&quot;,methods=[&#39;GET&#39;,&#39;POST&#39;])def req(): print(request.headers)
#模版继承和页面之间的调用@app.route(&quot;/bl&quot;)def bl(): return render_template(&quot;file_2.html&quot;)主ht
#文件操作:send_file,支持图片 视频 mp3 文本等@app.route(&quot;/img&quot;)def img(): return send_file(&quot;1.jpg&q