zoukankan      html  css  js  c++  java
  • 07.flask博客项目实战二之模板使用

    配套视频教程

    本文B站配套视频教程

    模板定义

    如有一个预期:html主页有一个 欢迎用户的标题。目前这个应用程序还没用户的概念,也没用户系统。但可用一个 模拟用户,用Python字典实现:

    user = {'username':'Miguel'}
    
    

    创建模拟对象 是一种有用的技术,使我们可专注于应用程序已有的部分,而不必担心尚不存在的部分。
    app/routes.py:从视图函数中返回完整的HTML页面

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

    在cmd中运行程序。更新视图功能,并查看应用程序在浏览器中的显示效果。

    C:UsersAdministrator>d:
    
    D:microblog>cd D:microblogvenvScripts
    
    D:microblogvenvScripts>activate
    (venv) D:microblogvenvScripts>cd D:microblog
    
    (venv) D:microblog>set FLASK_APP=microblog.py
    
    (venv) D:microblog>flask run
     * Serving Flask app "microblog.py"
     * Environment: production
       WARNING: Do not use the development server in a production environment.
       Use a production WSGI server instead.
     * Debug mode: off
     * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
    127.0.0.1 - - [02/Aug/2018 18:11:46] "GET / HTTP/1.1" 200 -
    
    

    很明显,HTML代码 和.py代码混在一起了,很不利于今后的维护、理解。就得将网络布局(呈现)应用程序的逻辑处理代码 分开/分离。模板在此闪亮登场!将助实现表示、业务逻辑的分离。

    Flask中,模板是作为单独的文件编写的,存放在应用程序 包内的 templates文件夹(约定俗成命名为 templates)下。

    即在app目录下创建templates文件夹:

    (venv) D:microblog>cd D:microblogapp
    
    (venv) D:microblogapp>mkdir templates
    
    

    在此目录下创建一个HTML文件index.html,它将和上方index()这个视图函数一样的视图功能。
    app/templates/index.html:主页面模板

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

    这是一个标准的、简单的HTML页面。但有一点跟我们写HTML代码不同是title标签、h1标签中的 {{ … }}两对花括号,在此它是个 占位符,作用是将表达式(如文字、数学式子、比较运算符等,其实在Python中是一个Python语句)打印到模板进行输出。具体参考Jinja2官网文档
    这些占位符表示HTML页面中可变的部分,并且只在运行时才知道。

    现在HTML页面的呈现已在HTML模板中了,这样接着就可简化一下视图函数index()了。修改routes.py文件
    app/routes.py:使用render_template()函数

    from app import app
    from flask import render_template#从flask包中导入render_template函数
    
    @app.route('/')
    @app.route('/index')
    def index():
        user = {'username':'Miguel'}
        return render_template('index.html', title='Home', user=user)
    
    

    将模板(index.html)转换为完整HTML页面的操作称之为 呈现(render,译作 递交、表达、给予,在此译作 “渲染”)。为了渲染模板,由从flask包中导入的render_template()完成,此函数“携带”模板文件名(index.html)、模板参数的变量列表,并返回相同的模板,不过其中所有占位符都替换为实际值。

    render_template()函数调用与Flask框架捆绑在一起的Jinja2模板引擎。Jinja2会用相应的值替换{{ ... }}块,这个相应的值由render_template()调用时提供的参数给出。
    参考:flask.render_template()

    控制结构----if条件、for循环、继承

    上述过程只是理解了:Jinja2模板引擎 如何在渲染过程中用实际值 替换 (模板中的)占位符。
    接下来将认识到更多 Jinja2在模板文件中支持的更多强大操作:if条件、for循环、继承等。
    源自官网的这句话:

    There are a few kinds of delimiters. The default Jinja delimiters are configured as follows:
    
    {% ... %} for Statements
    {{ ... }} for Expressions to print to the template output
    {# ... #} for Comments not included in the template output
    #  ... ## for Line Statements
    
    

    if、for、继承均在{% ... %}块中写控制语句。

    if条件

    形如:

    		{% if title %}
    			...语句块
    		{% else %}
    			...语句块
    		{% endif %}
    
    

    app/templates/index.html:模板中添加条件语句

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

    上述代码中if语句块的功能是:若视图函数index()没有传递title占位符变量的值,则index.html模板将会提供默认值(else语句块中),而不是显示空标题。
    尝试将routes.py中render_template()中的title='Home',删除。效果:图略

    for循环

    在模板中形如:

    {% for post in posts %}
    	...语句块
    {% endfor %}
    
    

    需求:登录用户可在主页中查看最新的帖子。
    实现:
    首先,用虚拟对象的方法来创建一些用户、帖子,以供显示。
    app/routes.py:视图函数中的假帖子

    from app import app
    from flask import render_template#从flask包中导入render_template函数
    
    @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)
    
    

    帖子列表 可包含任意数量的元素,由视图函数index()决定将在页面中显示的帖子数量。而模板index.html不能假设这有多少个帖子,因此它需要准备好以通用方式呈现视图发送来的尽可能多的帖子。在模板index.html中,用for循环遍历所有的帖子并呈现。
    app/templates/index.html:在模板中的for循环

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

    运行程序,图略

    模板继承

    形如:

    {% extends "base.html" %}
    
    {% block content %}
    	...
    {% endblock %}
    
    

    现在,大部分Web应用程序在页面顶部有一个导航栏,它常包含一些常用链接:如登录、退出、编辑个人资料等。可以很轻松地将导航栏添加到index.html模板,甚至更多的HTML页面中。但随着应用程序的增长(页面数量的增多),这些页面都将使用相同的导航栏,不可能每一个页面都增加一份相同的导航栏代码。

    Jinja2具有模板继承功能,完美解决上述问题。在实际操作中,将所有模板共有的页面布局部分移至基础模板中,其他模板则继承自它。

    实例:实现一个简单的导航栏,其他模板继承它。
    app/templates目录下创建一个基础模板文件 base.html。
    app/templates/base.html:带导航栏的基础模板

    <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 控制语句用于定义派生模板可自行插入的位置。块block 被赋予唯一的名字 content派生模板在提供其内容时可引用这个名称。

    修改index.html这个模板,让其继承base.html模板。
    app/templates/index.html:从基础模板继承

    {% extends "base.html" %}
    
    {% block content %}
    	<h1>Hello,{{ 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简化大部分内容。
    extends语句 建立了两个模板之间的继承关系,因此,Jinja2就会知道:当它被要求渲染index.html时,需要将其嵌入base.html中。这俩模板具有匹配的block语句 名称content,这就是Jinja2如何将两个模板合并为一个模板的方法。
    image.png

    运行程序,图略

    今后,当再需要为应用程序创建其他页面时,就可省去编写相同代码的麻烦,并让应用程序的所有页面共享相同的外观,而只需一个步骤:创建继承自base.html模板的派生模板

    目前为止,项目结构:

    microblog/
    	venv/
    	app/
    		templates/
    			base.html
    			index.html
    		__init__.py
    		routes.py
    	microblog.py
    

    参考
    https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-ii-templates

  • 相关阅读:
    webpack
    Js数组和字符串常用方法
    Vue.js 2.0 快速上手
    雅虎前端优化的35条军规
    前端问题大杂烩
    Java和js的区别,以及Java和c的区别
    前后端联调
    99%的人都理解错了HTTP中GET与POST的区别
    vue项目目录
    vuex入门
  • 原文地址:https://www.cnblogs.com/songboriceboy/p/13851915.html
Copyright © 2011-2022 走看看