在Python的Flask框架中使用模版的入门教程

来源:本网整理

Flask是一个使用Python编写的轻量级Web应用框架,凭借更灵活、轻便、安全且容易上手的特性,成为企业常用的Python框架之一。在完成Web前端、Linux以及MySQL相关的课程之后,专业的杭州Python学习班都会讲解Flask框架知识,以下是整理的相关知识点。Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于接收http请求并对请求进行预处理,然后触发Flask框架。开发人员基于Flask框架提供的功能对请求进行相应的处理,并返回给用户,如果要返回给用户复杂的内容时,需要借助jinja2模板来实现对模板的处理,即:将模板和数据进行渲染,将渲染后的字符串返回给用户浏览器。默认情况下,Flask不包含数据库抽象层、表单验证,或是其它任何已有多种库可以胜任的功能。然而,Flask支持用扩展来给应用添加这些功能,如同是Flask本身实现的一样。众多的扩展提供了数据库集成、表单验证、上传处理、各种各样的开放认证技术等功能。Flask框架的特点:1)Flask自由、灵活,可扩展性强,第三方库的选择面广,开发时可以结合自己最喜欢用的轮子,也能结合最流行最强大的Python库;2)入门简单,即便没有多少web开发经验,也能很快做出网站;3)非常适用于小型网站;4)非常适用于开发Web服务的API;5)开发大型网站无压力,但代码架构需要自己设计,开发成本取决于开发者的能力和经验。Flask框架运行解释1.app=Flask(_name_)创建Flask对象app,Flask类的构造函数只有一个必须指定的参数,即程序主模块或包的名字。在大多数程序中,Python的_name_变量就是所需要的值。2.@app.route('/')web浏览器把请求发送给Web服务器,Web服务器再把请求发送给Flask程序实例。程序实例需要知道对每个URL请求运行哪些代码,所以保存了一个URL到Python函数的映射关系。处理URL和函数之间的关系的程序称为路由。在Flask程序中定义路由的最简便方式,是使用程序实例提供的app.route修饰器,把修饰的函数注册为路由。route()装饰器告诉 Flask什么样的URL 能触发我们的函数。这和Java中的注释有异曲同工之妙。修饰器是Python语言的标准特性,可以使用不同的方式修改函数的行为。惯常用法是使用修饰器把函数注册为事件的处理程序。3.def index():函数index()函数放在@app.route('/')后面,所以就是把index()函数注册为路由。如果部署程序的服务器域名为http://127.0.0.1:5000/,在浏览器中访问http://127.0.0.1:5000/后,会触发服务器执行index()函数。4.@app.route('/user/')同@app.route('/'),如果部署程序的服务器域名为http://127.0.0.1:5000/,在浏览器中访问http://127.0.0.1:5000/后,会触发服务器执行下方修饰函数。5.app.run(debug=True)程序实例用run方法启动Flask继承Web服务器。6.if_name_='_main_'当Python解释器,读py文件,它会执行它发现的所有代码。在执行代码之前,它会定义一些变量。例如,如果这个py文件就是主程序,它会设置_name_变量为"_main_。如果这个py被引入到别的模块,_name_会被设置为该模块的名字www.zgxue.com防采集请勿采集本网。

 概述

from flask import Flask from flask.ext.sqlalchemy import SQLAlchemy app=Flask(_name_) app.config.from_object('config') db=SQLAlchemy(app) from app import views,models 注意生成的脚本已改动2个

如果你已经阅读过上一个章节,那么你应该已经完成了充分的准备工作并且创建了一个很简单的具有如下文件结构的Web应用:

当然可以自己写代码连接到数据库,并操作之。使用Sqlalchmy的目的主要是ROM吧。工作重心可以放在业务处理上,而不用太操心数据库的Flask的文档里,就有说怎么直接通过Python操作数据库的内容。

 

这样做的缺点是,你将不能使用像Flask-Mail,但imo,它不是太好,以至于如此密切地关联到Flask生态系统;通过使用Flask-Mail在标准的非Flask邮件库中获得什么?此外,分解应用程序可以更容易扩展单个组件与

microblog

from sqlalchemy import textsql=text('select name from penguins')result=db.engine.execute(sql)思路就是 用flask 执行原生sql语句 写好查询A数据库到B数据库的语句 直接执行即可,效率最高

 

这样做的缺点是,你将不能使用像Flask-Mail,但imo,它不是太好,以至于如此密切地关联到Flask生态系统;通过使用Flask-Mail在标准的非Flask邮件库中获得什么?此外,分解应用程序可以更容易扩展单个组件与

   |-flask文件夹

 

这样做的缺点是,你将不能使用像Flask-Mail,但imo,它不是太好,以至于如此密切地关联到Flask生态系统;通过使用Flask-Mail在标准的非Flask邮件库中获得什么?此外,分解应用程序可以更容易扩展单个组件与

   |-<一些虚拟环境的文件>

 

这样做的缺点是,你将不能使用像Flask-Mail,但imo,它不是太好,以至于如此密切地关联到Flask生态系统;通过使用Flask-Mail在标准的非Flask邮件库中获得什么?此外,分解应用程序可以更容易扩展单个组件与

   |-app文件夹

 

这样做的缺点是,你将不能使用像Flask-Mail,但imo,它不是太好,以至于如此密切地关联到Flask生态系统;通过使用Flask-Mail在标准的非Flask邮件库中获得什么?此外,分解应用程序可以更容易扩展单个组件与

   |  |-static文件夹

 

这样做的缺点是,你将不能使用像Flask-Mail,但imo,它不是太好,以至于如此密切地关联到Flask生态系统;通过使用Flask-Mail在标准的非Flask邮件库中获得什么?此外,分解应用程序可以更容易扩展单个组件与

   |  |-templates文件夹

 

这样做的缺点是,你将不能使用像Flask-Mail,但imo,它不是太好,以至于如此密切地关联到Flask生态系统;通过使用Flask-Mail在标准的非Flask邮件库中获得什么?此外,分解应用程序可以更容易扩展单个组件与

   |  |-__init__.py文件

 

这样做的缺点是,你将不能使用像Flask-Mail,但imo,它不是太好,以至于如此密切地关联到Flask生态系统;通过使用Flask-Mail在标准的非Flask邮件库中获得什么?此外,分解应用程序可以更容易扩展单个组件与

   |  |-views.py文件

 

这样做的缺点是,你将不能使用像Flask-Mail,但imo,它不是太好,以至于如此密切地关联到Flask生态系统;通过使用Flask-Mail在标准的非Flask邮件库中获得什么?此外,分解应用程序可以更容易扩展单个组件与

   |-tmp文件夹

 

这样做的缺点是,你将不能使用像Flask-Mail,但imo,它不是太好,以至于如此密切地关联到Flask生态系统;通过使用Flask-Mail在标准的非Flask邮件库中获得什么?此外,分解应用程序可以更容易扩展单个组件与

   |-run.py文件

亲,想要运行这个程序么?那就运行这个run.py文件,然后在你的浏览器里边打开http://localhost:5000这个地址.

我们在后面的章节会不断地从前一章节结束的地方继续开发我们的应用,所以你要确保你的环境已经正确安装,并且你的应用能够正常运行.

 

这样做的缺点是,你将不能使用像Flask-Mail,但imo,它不是太好,以至于如此密切地关联到Flask生态系统;通过使用Flask-Mail在标准的非Flask邮件库中获得什么?此外,分解应用程序可以更容易扩展单个组件与

为什么我们需要使用模板系统

让我们来考虑一下,我们接下来怎么样扩展我们的小程序.

我们要在微博应用里边实现一个非常基本的功能,在首页上面显示一个欢迎已登录用户的标题.暂且忽略当前应用里边没有用户的状况,我将会在稍后解决这个问题.

要显示一个美观大方的标题,最简单的方法就是改变我们提供视图的方式来显示一些HTML代码,不如这样子:\

 

这样做的缺点是,你将不能使用像Flask-Mail,但imo,它不是太好,以至于如此密切地关联到Flask生态系统;通过使用Flask-Mail在标准的非Flask邮件库中获得什么?此外,分解应用程序可以更容易扩展单个组件与

from app import app @app.route('/')@app.route('/index')def index(): user = { 'nickname': 'Miguel' } # fake user return '''<html> <head> <title>Home Page</title> </head> <body> <h1>Hello, ''' + user['nickname'] + '''</h1> </body></html>

现在,在你的浏览器里面刷新一下看看,是不是很爽?

 

这样做的缺点是,你将不能使用像Flask-Mail,但imo,它不是太好,以至于如此密切地关联到Flask生态系统;通过使用Flask-Mail在标准的非Flask邮件库中获得什么?此外,分解应用程序可以更容易扩展单个组件与

因为我们这个小程序还支持用户功能,所以咱用了一个用户占位对象,通常它被亲切的称呼为假数据或测试数据。它可以让我们关注程序中急需解决的部分。

爽完了,面对实际吧,我希望你会觉得上面这个混合着html代码的小程序相当恶心。想想看,如果你用一些动态内容生成的一个复杂的HTML页面,并且想要在由这样的程序组成的网站中改变一些页面内容,这将会一件非常蛋疼的事情。

模板系统拯救世界

如果保持业务逻辑和表现的分离,你的网站结构将会组织的更好。不要不信,如果你用python完成了业务代码,你甚至可以请一个网站设计师帮你完成剩下的部分。模板系统就是帮你实现业务和表现分离的。

让我们完成第一个模板(fileapp/templates/index.html):

 

这样做的缺点是,你将不能使用像Flask-Mail,但imo,它不是太好,以至于如此密切地关联到Flask生态系统;通过使用Flask-Mail在标准的非Flask邮件库中获得什么?此外,分解应用程序可以更容易扩展单个组件与

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

如你所见,我们只是写了一个普通的HTML页面,唯一跟HTML有区别的就是里面掺杂了一些以 {{ ... }} 组成的动态内容占位符。

现在让我们来看看视图函数中是如何处理这个模板的(fileapp/views.py):

 

这样做的缺点是,你将不能使用像Flask-Mail,但imo,它不是太好,以至于如此密切地关联到Flask生态系统;通过使用Flask-Mail在标准的非Flask邮件库中获得什么?此外,分解应用程序可以更容易扩展单个组件与

from flask import render_templatefrom app import app @app.route('/')@app.route('/index')def index(): user = { 'nickname': 'Miguel' } # fake user return render_template("index.html", title = 'Home', user = user)

测试这段程序的重点就是看看模板系统是如何工作的。你可以比较浏览器中渲染后的html页面源码与模板文件源码之间的区别。

在上面的程序中,我们从 Flask 框架 import 了一个叫 render_template 的新函数,并用这个函数来渲染模板。并给这个函数赋予了模板文件名和一些变量作为参数。它将导入的变量替换掉模板中的变量占位符,并返回渲染后的模板。

让我们了解的更深入点。在 Flask 底层,render_template 函数实际上是调用了 Flask 的一个组件: Jinja2 模板处理引擎。是 Jinjia2 用导入的变量替换掉了模板中对应的 {{ ... }} 代码块。

模板中的流程控制

Jinja2 模板系统还支持流程控制语句,我们来尝试一下在模板中添加一个 if 流程控制语句 (fileapp/templates/index.html):

 

这样做的缺点是,你将不能使用像Flask-Mail,但imo,它不是太好,以至于如此密切地关联到Flask生态系统;通过使用Flask-Mail在标准的非Flask邮件库中获得什么?此外,分解应用程序可以更容易扩展单个组件与

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

现在我们的模板文件有点智能了。如果我们在视图函数中忘了定义页面标题变量 title,它将会使用自已的标题替代。把视图函数中 render_template 里的 title 变量取消试试,看看这个 if 流程语句是如何工作的。

模板中使用循环

也许用户想在他的主页上展示好友最近写的文章,有点像人人,或者新浪微博那样的好友动态,接下来我们就要看看如何来完成这个功能。

首先,创建用户和文章 (fileapp/views.py):

 

这样做的缺点是,你将不能使用像Flask-Mail,但imo,它不是太好,以至于如此密切地关联到Flask生态系统;通过使用Flask-Mail在标准的非Flask邮件库中获得什么?此外,分解应用程序可以更容易扩展单个组件与

def index(): user = { 'nickname': 'Miguel' } # fake user posts = [ # fake array of posts { 'author': { 'nickname': 'John' }, 'body': 'Beautiful day in Portland!' }, { 'author': { 'nickname': 'Susan' }, 'body': 'The Avengers movie was so cool!' } ] return render_template("index.html", title = 'Home', user = user, posts = posts)

用数组存储用户的文章,每一个数组元素都是一个字典,如上代码所示,这个dict的key是author和body,用来存储文章的作者和文章内容。当我们决定使用数据库来存储这些信息时,这个字典的key可以隐射为表的一个字段,这里为了给大家演示模板的使用,没有使用数据库相关的技术,简单地使用字典和数组模拟用户和他的好友最近发表的文章。

 

这样做的缺点是,你将不能使用像Flask-Mail,但imo,它不是太好,以至于如此密切地关联到Flask生态系统;通过使用Flask-Mail在标准的非Flask邮件库中获得什么?此外,分解应用程序可以更容易扩展单个组件与

我们的模板文件现在有了一个新问题。我们刚刚创建了一个包含用户文章的内容数据,这个数组可能包含任意数量的文章。怎样才能让模板根据这个数组的数量自动渲染内容。

要解决这个问题,就需要一个新的流程控制语句:for循环。让我们来把 for循环添加到模板文件 (fileapp/templates/index.html)

 

这样做的缺点是,你将不能使用像Flask-Mail,但imo,它不是太好,以至于如此密切地关联到Flask生态系统;通过使用Flask-Mail在标准的非Flask邮件库中获得什么?此外,分解应用程序可以更容易扩展单个组件与

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

很简单吧,你还可以在数组中添加更多的内容看看效果。

 

这样做的缺点是,你将不能使用像Flask-Mail,但imo,它不是太好,以至于如此密切地关联到Flask生态系统;通过使用Flask-Mail在标准的非Flask邮件库中获得什么?此外,分解应用程序可以更容易扩展单个组件与

模板继承

接来下,我们需要给这个微博(microblog)添加一个导航菜单,里面包含 修改个人资料,退出登录 等类似的链接。

直接在 index.html 模板文件中直接加入这个导航条也是可行的,但是当我们有很多模板文件都包含这个导航条时,就会陷入为了修改导航条的某个地方而不得不在多个文件中往返编辑的尴尬境地。当包含这个导航条的文件越来越多时,你想死的心就会有了。

我们可以使用 Jinja2 的模板继承功能,它可以使我们把模板中一些公共的内容组合在一起创建一个基础模板,然后让其它模板继承这个基础模板。

我们先来定义一个基础模板,里面包含了导航条和那个最开始写的关于页面标题(title)的流程控制语句。(fileapp/templates/base.html):

 

这样做的缺点是,你将不能使用像Flask-Mail,但imo,它不是太好,以至于如此密切地关联到Flask生态系统;通过使用Flask-Mail在标准的非Flask邮件库中获得什么?此外,分解应用程序可以更容易扩展单个组件与

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

在这个模板中,我们使用了 block 控制语句来定义继承模板内容的显示位置。注意:这个 block 语句中设置的名称必须唯一。

接下来让我们修改一下 index.html 模板,让它继承于刚刚添加的基础模板 base.html (fileapp/templates/index.html):

 

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

基础模板 base.html 帮我们搞定了页面结构和公共内容,所以这个 index.html 模板就成了这幅衰样了。extends 语句使两个模板关联了起来。Jinja2 在渲染 index.html 模板时,发现 extends 语句,就会自动先引入 base.html 基础模板,并对两个模板中名为 content 的 block 语句进行匹配。Jinja2知道如何把两个模板合并到一起。我们以后创建新的模板时,同样也会使用这种从基础模板继承的方法。

结束语

如果你想节省时间,懒得敲代码,可以从以下地址下载本章内容的示例代码:

下载地址:microblog-0.2.zip

灰常不幸的是,关系型数据库对全文检索的支持没有被标准化。不同的数据库通过它们自己的方式来实现全文检索,而且SQLAlchemy在全文检索上也没有提供一个好的抽象。我们现在使用SQLite作为我们的数据库,所以我们可以绕开SQLAlchemy而使用SQLite提供的工具来创建一个全文检索索引。但这么做不怎么好,因为如果有一天我们换用别的数据库,那么我们就得重写另一个数据库的全文检索方法。所以我们的方案是,我们将让我们现有的数据库处理常规数据,然后我们创建一个专门的数据库来解决全文检索内容来自www.zgxue.com请勿采集。

免责声明 - 关于我们 - 联系我们 - 广告联系 - 友情链接 - 帮助中心 - 频道导航
Copyright © 2017 www.zgxue.com All Rights Reserved