构建一个Web应用:利用search4letters这个函数,让人们都可以在web上访问这个函数
区分好web请求与web响应:
1、用户在浏览器输入一个web地址后单击超链接,
2、浏览器会将用户的动作转换为一个web请求,通过互联网发送到一个web服务器。
3、web服务器接收到web请求后会做两件事:
如果请求知识请求一个静态内容(HTML文件或图像等),web服务器就会找到这个资源并将它作为一个web响应返回去给web浏览器;
如果请求的是动态内容(搜索结果或购物车等),web服务器就会运行一些代码来生成web响应再返回去给web浏览器。
4、web服务器通过互联网江响应发回给正在等待的web浏览器
5、浏览器接收到web响应并显示在用户屏幕上
分析search4letters:
def search4letters(phrase:str,letters:str='aeiou') -> set:
这个函数需要至少1个但不能超过2个参数,phrase和letters(要在phrase中搜索letters)。且letter参数是可选的(默认为aeiou)
Web应用框架flask
安装Flask:
windows:
打开命令行提示窗口,作为管理员运行(右键点击鼠标选择作为管理员运行),执行命令
c:\>py -3 -m pip install flask
回车后跑完会出现
Successfully installed Jinja-版本号 Markupsafe-版本号 Werkzeug-版本号 flask-版本号
Flsak 依赖的4个模块 Jinja-版本号 Markupsafe-版本号 Werkzeug-版本号 flask-版本号
轻量级规模小易使用是Flask模块的特性
启动服务器:
需要复习掌握常用命令行
第一种方法
使用win+R可以调出cmd,或者在目标文件的文件夹里面按住shift同时单击鼠标右键选择Open command window here
>d:(变动位置)
>cd (通过文件属性来查看文件的所属位置)(win10以上可以直接复制粘贴ctrl+c/v,win10以下只能右键复制粘贴)
>cd 文件位置 >python(空格) 文件名.py(如untitled.py) 启动python文件,如果没有配置python文件启动运行环境,就需要去以管理员身份更改PATH配置环境将python文件移动到pyrhon.exe所处的指定的根目录之下
第二种方法
使用Anoconda Prompt
>cd 位置粘贴(与第一种方法一样)
检查是否已经安装好flask框架
>flask
回车后代码跑起来结束就是已经安装好,如果没有的话就需要使用
pip install flask
从现在开始都会由Flask接管,只要内置Web服务器完成任何操作,都会在屏幕上显示状态校系。启动之后,Flask Web服务器会立即确认它已经启动,开始运行并在Flask测试Web地址(127.0.0.1)和协议端口(5000)上等待为Web请求提供服务。
启动服务器
>cd (进入目录路径) >python(空格)hello-flask.py(启动文件两种方法:第一种是将文件位置复制粘贴,第二种是将文件直接拖进命令行里面)
接着就会出现
*Running on http://127.0.0.1:5000/(Press CTRL+C to quit)(IP地址)
但是会报错
5000是端口号,网页默认是80不需要写出来
flask若在单机上是找不到服务器的
如果IP输入5000/dothiswork.html ,服务器就会多出一行404报错,因为没有5000的话用户就会找不到服务器
我们把IP地址输入打开也是可以跳转到网页的,因为已经Running起来了
将IP地址(URL)在浏览器上面输入并回车就会跳转到相应的web请求后返回的web响应页面,服务器就已经启动成功了。这就是Web浏览器和Web服务器交互。接着终端窗口会出现新的状态消息
200-
接下来我们编写一下代码文件
将代码输进去来获得第一个hello_flask.py文件
from flask import Flask
app = Flask (__name__)
@app.route('/')
def hello() -> str:
return 'Hello world from Flask!'
app.run()
不能在IDLE中运行这个Flask代码,IDLE不能很好完成这种大的代码段,最好在系统的命令行上直接通过解释器运行代码。服务器启动流程看上面。
分析代码行
第一行:导入flask模块的Flask类
from flask import Flask
也可以写成
import flask
flask.Flask
第二行:创建一个Flask类型的对象,把它赋给app变量。
app = Flask (__name__)
Flask使用一个奇怪的参数 __ name __(双下划线),设置为当前活动模块的名字。创建一个新的Flask对象时,Flask类需要知道 __ name __的当前值,必须作为一个参数传递这个值。在这里需要注意”dunder name“的使用”双下划线,name,双下划线“
定制对象是app也就是实例,flask是变量类型代表网页
这里没有调用hello函数,并不是往服务器上放代码,而是@修饰符帮我们做了这一步骤
第三行:修饰符(decorator)可以调整一个现有函数的行为,而无需修改这个函数的代码(函数得到修饰,允许你根据需要为已有的一些代码增加额外的行为)
@app.route('/')
修饰符route前面有@符号前缀,可以调整一个已有函数的行为
后面(‘/’)是URL:127.0.0.1:5000
本行是通过app变量使用Flask的route修饰符。route修饰符允许你江一个URL Web 路径与一个已有的python函数关联。URL"/"与下一行代码中定义的函数关联,函数命名为hello,当一个只想“/”URL的请求到达服务器时route修饰符会安排Flask web服务器调用这个函数。route修饰符会等待所修饰的函数生成的输出,再将输出返回给服务器,服务器再将输出返回给正在等待的Web浏览器。
记住:Flask能为你完成所有这些工作,我们需要做的就是写一个函数生成我们想要的输出。Flask和route修饰符会负责所有具体细节。
注:@修饰符为上下文做了做了关联,当执行5000时,前面有了@自动帮你执行后面的函数,返回了Hello world(自动默认执行)
第四行:定义route修饰符修饰的函数,返回字符串 ->str
调用hello函数时返回消息“Hello world from Flask!”
def hello() -> str:
return 'Hello world from Flask!'
第五行:通过调用run来实现得到赋给app变量的Flask对象后,让Flask开始运行它的web服务器
app.run()
可以看到服务器返回了url,run后面的()。在服务器上跑起来,跑的是代码。请求的是一个str,返回值也是一个str。
这时,Flask会启动内置Web服务器,并在服务器中运行Web应用代码。Web服务器接收到指向“/”URL的任何请求时,会响应“Hello worldfrom Flask!”消息,而指向其他URL请求会得到404“Resourse not found”错误消息。
输入http://127.0.0.1:5000/doesthiswork.html,是没有页面并且服务器会同步报错404
浏览器显示“Not Found”,终端窗口运行的Web应用也会用一个适当的消息更新状态
在这里Flask为你做了什么:
他提供了一种机制,利用这种机制我们可以执行任何已有的python函数,并在一个Web浏览器中显示他的输出
为了向Web应用中增加更多功能,所要做的只是要确定希望将函数与哪个URL关联,然后在完成具体工作的函数上面编写一个适当的@app.route修饰符行
我们将使用上一章节的search4letters函数
我们现在来修改hello_flask.py来包含第二个URL: /search4。将这个URL与一个名为do_search的函数关联,它会从vsearch模块调用search4letters函数,让do_search函数返回搜索时确定的结果:在短语”life,the universe,and everything“中搜索字符串‘eiru,!’
注意:search4letters返回的结果是一个pytho集合,向等待的Web浏览器返回任何结果之前,一定要通过调用str内置函数(BIF)将结果强制转换为一个字符串。因为浏览器希望得到文本数据而不是一个python集合
修改后的
hello_flask2.py
from flask import Flask
from vsearch import search4letters
app = Flask (__name__)
@app.route('/')
def hello() -> str:
return 'Hello world from Flask!'
@app.route('/search4')
def do_search() -> str:
return str(search4letters('life,the universe,and everything','eiru,'))
app.run()
增加一到第二行:
from vsearch import search4letters
在调用之前,需要从"vsearch"模块导入"search4letters"函数
增加二:
@app.route('/search4')
第二个修饰符建立"/search4"URL
增加三:
def do_search() -> str:
return str(search4letters('life,the universe,and everything','eiru,'))
”do_search“函数调用"search4letters",然后将结果作为字符串返回
想要测试新功能需要重启 Flask Web 应用,因为现在运行的是老版本的代码
返回到终端窗口,同时按下”Ctrl + c“,Web应用会停止,回到操作系统提示符,按向上箭头找到前一个命令(之前启动hello_flask.py的命令),回车
再次显示初始的Flask状态消息,确认更新后的Web应用在等待请求
输入http://127.0.0.1:5000正常
输入http://127.0.0.1:5000/search4正常
这是因为没有修改与默认‘/’URL关联的代码,所以这个功能仍能正常工作,会显示"Hello world from Flask!"消息——http://127.0.0.1:5000
如果在浏览器的地址栏输入”http://127.0.0.1:5000/search4“,就会看到调用了search4letters的结果
调用"search4letters"的结果,但是确实证明了使用"/search4"URL会调用函数并返回结果
set对象没有被调用,return返回字符串,强制为字符串,是一种集合类型的字符串
函数只会执行相近数,所以服务器会有多个页面,通过“/”反斜杠(默认IP地址)为它指定一个名字,我们在服务器上面搭建了两个东西分别是“/”,“/search4”
显示"search4"是"get"
200是正常
500服务器过载
404网页找不到
函数的修饰符只能够找到函数
团队的项目是将其他同学的作为一个模块导进来:
将py文件打包导出为模块,用主的py文件来做操作,基本上一个函数一个页面,注册信息是主界面,其他是分界面,每个同学都有页面前端和后端,项目都部署在码云里面并且要活跃该项目。但是必须要弄清楚主程序的入口和项目逻辑在哪里?
url解释:
用来访问Web 应用中的URL中的127.0.0.1和:5000是什么意思
为什么请求的是返回值而不是网页呢?Web应用需要一个Web页面接收输入,还需要一个Web页面显示结果(将输入提供给search4letters函数得到的结果)
关键是这两段的代码分别响应了两个网页
@app.route('/')
def hello() -> str:
return 'Hello world from Flask!'
@app.route('/search4')
def do_search() -> str:
return str(search4letters('life,the universe,and everything','eiru,'))
这就要用到两个基模板了,在用基模板之前需要先修改hello函数来返回HTML表单,再修改do_search函数接收这个表单的输入,再调用search4letters函数,最后由do_search将结果作为另一个Web页面返回
利用模板引擎,可以应用面向对象的继承和重用概念来生成文本数据,Web页面也是其中之一。
两个基模板(网站的外观可以在一个顶层HTML模板中定义,这称为基模板,其它HTML页面继承这个模板。如果对基模板做了某个修改,这个修改就会在继承该模板的所有HTML页面中体现)
Flask提供的模板引擎为Jinja2。
基模板 base.html
注意标注出来的{{和}}之间,{%和%}包围是针对Jinja2模板引擎的
<!doctype html>
<html>
<head>
<title>{{ the_title }}</title>
<link rel="stylesheet" href="static/hf.css" />
</head>
<body>
{% block body %}
{% endblock %}
</body>
</html>
特别注意
<!doctype html> #标准HTML5标记
{{ the_title }} #这是一个Jinja2指令,指示将在呈现之前提供的一个值(可以把它想象成是模板的一个参数)
<link rel="stylesheet" href="static/hf.css" /> #样式表定义了所有Web页面的外观
{% block body %} #Jinja2指令指示要在呈现之前替换这里的HTML块,这要由继承这个模板的页面来提供
{% endblock %} #Jinja2指令指示要在呈现之前替换这里的HTML块,这要由继承这个模板的页面来提供
有了基模板后,可以使用Jinja2的extends指令继承这个模板。这样继承模板的HTML文件只需要提供基模板中命名块的HTML。在这里我们只有一个命名块:body
第一个页面标记:entry.html
实现用户与这个HTML表单交互来提供Web应用需要的phrase和letters的值
这个文件中没有重复基模板中的样板HTML,因为extends指令已经为我们包含了这些标记。我们需要提供这个文件特定的HTML,所以要在名为body的Jinja2块中提供标记
{% extends 'base.html' %} #这个模板继承了基模板,为名为"body"的块提供了一个替代块
{% block body %}
<h2>{{ the_title }}</h2>
<form method='POST' action='/search4'>
<table>
<p>Use this form to submit a search request:</p>
<tr><td>Phrase:</td><td><input name='phrase' type='TEXT' width='60'></td>
</tr>
<tr><td>Letters:</td><td><input name='letters' type='TEXT' value='aeiou'></td>
</tr>
</table>
<p>When you're ready, click this button:</p>
<p><input value='Do it!' type='SUBMIT'></p>
</form>
{% endblock %}
特别注意:
{% extends 'base.html' %}
{% block body %}
{{ the_title }}
{% endblock %}
第一个页面标记:results.html
实现呈现搜索的结果
{% extends 'base.html' %} #与entry.html类似,这个模板也继承了基模板,另外为名为"body"的块提供了一个替代块
{% block body %}
<h2>{{ the_title }}</h2>
<p>You submitted the following data:</p>
<table>
<tr><td>Phrase:</td><td>{{ the_phrase }}</td></tr>
<tr><td>Letters:</td><td>{{ the_letters }}</td></tr>
</table>
#注意the_phrase,the_letters,the_results 这些额外的参数值,在呈现之前是需要赋值给他们的。
<p>When "{{the_phrase }}" is searched for "{{ the_letters }}", the following
results are returned:</p>
<h3>{{ the_results }}</h3>
{% endblock %}
特别注意:
{% extends 'base.html' %}
{% block body %}
{{ the_title }}
{{ the_phrase }}
{{ the_letters }}
{{the_phrase }}
{{ the_letters }}"
{{ the_results }}
{% endblock %}
Web应用需要呈现两个Web页面,现在已经有了两个模板。这两个模板都继承自基模板,因此继承了基模板的外观,现在就是要呈现这些页面。两个页面的标题将在呈现时提供标题值来取代{{ the_title }}指令。可以把双大括号中的各个名字想成是模板的一个参数 P216
新增一个Flask的函数 render_template 的函数:如果指定一个模板名和所需的参数,调用这个函数时会返回一个HTML串,为此需要将这个函数名增加到从flask模块导入的函数列表中,再根据需要进行调用
将hello_flask.py文件的名字改为vsearch4web.py
#这是hello_flask.py里的代码
from flask import Flask
from vsearch import search4letters
app = Flask(__name__)
@app.route('/')
def hello() -> str:
return 'Hello world from Flask!'
@app.route('/search4')
def do_search() -> str:
return str(search4letters('life, the universe, and everything', 'eiru,!'))
app.run()
为了呈现entry.html模板中的HTML表单,修改vsearch4web.py
#这是vsearch4web.py里的代码
from flask import Flask, render_template
from vsearch import search4letters
app = Flask(__name__)
@app.route('/')
def hello() -> str:
return 'Hello world from Flask!'
@app.route('/search4')
def do_search() -> str:
return str(search4letters('life, the universe, and everything', 'eiru,!'))
@app.route('/entry')
def entry_page() -> 'html':
return render_template('entry.html',
the_title='Welcome to search4letters on the web!')
app.run()
特别注意:
修改1:导入render_template函数
将“render_template”增加到从“flask”模块导入的函数列表
from flask import Flask, render_template
修改2:创建一个新的URL,这里就是/entry
每次你的Flask web应用中需要一个新的URL时,都要增加一个新的@app.route行。我们会在do_search函数之后,app.run()代码行前面增加这一行,为Web应用增加一个新URL
@app.route('/entry')
修改3:创建一个函数返回正确呈现的HTML
将这个函数增加到新“@app.route”行下面
有了@app.route行之后,可以为新增的URL关联代码,为此要创建一个完成具体工作的函数。这个函数要调用render_template函数(并返回它的输出),这里要传入模板文件名(这里是entry.html)以及模板所需的参数值(在这里需要为the_title提供一个值)
entry.html 提供要呈现的模板名
the_title='Welcome to search4letters on the web! 提供一个值与“the_title”参数关联
def entry_page() -> 'html':
return render_template('entry.html',
the_title='Welcome to search4letters on the web!')
现在暂时还不能够运行。基模板引用一个名为hf.css的样式表,这个样式表要放在一个名为static的文件夹中,也就是说hf.css文件必须存在必须放在static文件夹中static文件夹必须放在webapp文件夹中,在基模板中有看到hf.css文件的路径
<link rel="stylesheet" href="static/hf.css" />
并且还要将基模板和两个模板(base.html、entry.html、results.html)都存储在templates文件夹中,templaes文件夹也在webapp文件夹中.
所以到现在有一个webapp文件夹,有5个文件(vsearch4web.py、hf.css、base.html、entry.html、results.html)和2个文件夹(static、templates)
放置好文件夹就可以运行了,先ctrl+c退出服务器停止web应用,再按向上箭头回到上一步输入文件名后按回车,出现running就是新代码开始运行,等待为请求提供服务。但是出了点错误
这段代码仍然支持 / 和 /search4 URL,如果使用一个浏览器请求这些URL,会得到相同的响应,但是如果输入
http://127.0.0.1:5000/entry
浏览器中显示的响应将是所呈现的HTML表单
命令行提示窗口会显示另外两个状态栏:
一个对应/entry请求(请求HTML表单)
另一个与浏览器对hf.css样式表的请求有关(请求样式表)
但是如果输入一个短语并调整要查找的字母值,点击do it 按钮时会出错
看到命令提示符我们需要区分get和post的不同之处,首先要了解http状态码
当web应用出现问题,web服务器就会响应一个http状态码并发送到浏览器中,http是允许web浏览器和服务器通信的协议,实际上,每个web请求都会生成一个http状态码响应 P222
100类-信息消息
200类-成功消息
300类-重定向消息
400类-客户端错误消息
500类-服务器错误消息
这里的405状态码指示客户端(浏览器)使用了这个服务器不允许的一个http方法来发送请求。http方法我们需要掌握2种:GET和POST
GET方法:
浏览器通常使用这个方法从web服务器请求一个资源,目前web应用中所有URL都支持GET,这是Flask默认的http方法
POST方法:
允许web浏览器向服务器通过http发送数据,这与HTML<form>标记紧密关联,可以让Flask Web 应用从浏览器接收提交的数据,为此需要在@app.route行上提供一个额外的参数
再次修改vsearch4web.py,调整与Web应用/search4 URL 对应的@app.route行,来接收所提交的数据
@app.route修饰符除了接收URL作为第一个参数,还接收其他可选的参数。其中有methods参数,这会列出URL支持的http方法。Flask默认对所有的URL都支持GET方法,但是,如果methods参数赋值为一个要支持的http方法列表,就会覆盖这个默认行为
@app.route('/search4') #这里没有指定要支持的http方法,所以Flask默认为GET
要让/search4 URL 支持POST,需要为这个修饰符增加methods参数,并为它赋一个http方法列表,也就是希望这个URL支持的所有http方法。
@app.route('/search4',methods=['POST']) #指出/search4URL现在只支持POST方法(意味着不再支持GET方法)
服务器就不会再显示“Method Not Allowed”,现在与html表单关联的POST与@app.route代码行上的POST一致
在entry.html里面有写到<form method='POST' action='/search4'>
在vsearch4web.py里面写到@app.route('/search4',methods=['POST'])
但是要注意,html使用的是"method"(单数),而Flask使用的是"methods"(复数)
如果你想要URL既支持GET方法又支持POST方法,只需要把要支持的http方法名增加到赋给methods参数的列表中
为/search4 URL增加GET和POST
@app.route('/search4',methods=['GET','POST'])
修改后的代码
#这是vsearch4web.py里的代码
from flask import Flask, render_template
from vsearch import search4letters
app = Flask(__name__)
@app.route('/')
def hello() -> str:
return 'Hello world from Flask!'
@app.route('/search4',methods=['POST'])
def do_search() -> str:
return str(search4letters('life, the universe, and everything', 'eiru,!'))
@app.route('/entry')
def entry_page() -> 'html':
return render_template('entry.html',
the_title='Welcome to search4letters on the web!')
app.run()
为了提高修改过程中服务器上线和下线的效率,Flask允许在调试模式下运行Web应用,每次Flask注意到代码已经改变时(通常是做了修改并且已经保存),就会自动重启你的web应用
打开调试模式需要在vsearch4web.py的最后一行代码修改如下
app.run(debug=True) #打开调试模式
在停止web应用后再次打开服务器上线,不会再显示“Running on ...”,Flask会显示3个状态行
如果代码改变,Web应用会自动重启
*Restarting with stat
*Debugger is active!
*Debugger pin code:(调试器pin码不同机器不一样)
再一次输入http://127.0.0.1:5000/entry进行与Web应用交互,“Method Not Allowed”没有了,出现了返回的页面,但是发现在尝试多次输入任何不同的短语,每次显示返回的结果都是一样的,无论输入什么样的单词放回去的结果都是一样的
返回总是返回相同的字符集“u,e,逗号,i,r”,回头查看请求/seaarch4 URL时执行的代码,问题就在于phrase和letters的值硬编码写在函数中
@app.route('/search4',methods=['POST'])
def do_search() -> str:
return str(search4letters('life, the universe, and everything', 'eiru,!'))
无论在html表单中键入什么,这个代码都总是使用这些硬编码的值
html表单将数据提交到web服务器,需要用Flask提供的内置对象request来访问所提交的数据。request对象中的from字典属性可以访问从浏览器提交的html表单数据,form同样支持中括号记法:要访问表单中的一个数据,可以把表单元素的名字放在中括号中。
#访问表单元素数据
request.form['phrase'] #访问输入到html表单的phrase
request.form['letters'] #访问输入到html表单的letters
同样在vsearch4web.py中需要导入request对象,根据需要从request.form访问数据,并且把do_search函数的硬编码的数据值替换为表单数据,这样就确保了在每次html表单中使用不同的phrase和letters值时,从web应用返回的结果会相应地调整
#这是vsearch4web.py里的代码
from flask import Flask, render_template,request
from vsearch import search4letters
app = Flask(__name__)
@app.route('/')
def hello() -> str:
return 'Hello world from Flask!'
@app.route('/search4',methods=['POST'])
def do_search() -> str:
phrase = request.form['phrase'] #创建两个新变量“phrase”,“letters”
letters = request.form['letters'] #并把HTML表单的数据赋至新创建的变量
return str(search4letters(phrase, letters)) #然后在"search4letters"调用中使用这些变量
@app.route('/entry')
def entry_page() -> 'html':
return render_template('entry.html',
the_title='Welcome to search4letters on the web!')
app.run()
保存好vsearch4web.py后,在命令行提示窗口可以看到web应用生成的状态消息
Flask调试器已经发现代码有修改,重启了web应用。但是只有正确完成了代码修改,才会自动重新加载。如果代码有错误web应用就会转到命令行提示窗口。要想再次运行就需要修正代码错误并且手动重启web应用(按上箭头再按回车)
命令行自动更新?很遗憾没有出现重新加载,我需要手动加载,手动加载后就已经可以输入单词显示正常了
但是有时候会出现空集合显示为set(),这是因为寻找的字母都没有出现过
现在任何web浏览器都可以提交一个phrase/letters组合,web应用会代表我们调用search4letters并返回结果。
但是返回的结果生成的输出只是一个空白的页面上有字母而已还不是一个完整的html web页面,它还只是一个原始的数据,作为文本返回给正在等待的浏览器(它会将这个结果显示在屏幕上)
现在entry.html已经生成表单html页面,但是results.html还没有生成html页面,只是江结果显示为原始数据
回忆前面的Jinja2模板技术时,提供了两个html。第一个是entry.html用于生成表单;第二个是results.html用来显示结果
下面就用resluts.html模板将原始数据输出转换为html
回顾results.html模板内容
{% extends 'base.html' %}
{% block body %}
<h2>{{ the_title }}</h2>
<p>You submitted the following data:</p>
<table>
<tr><td>Phrase:</td><td>{{ the_phrase }}</td></tr>
<tr><td>Letters:</td><td>{{ the_letters }}</td></tr>
</table>
<p>When "{{the_phrase }}" is searched for "{{ the_letters }}", the following
results are returned:</p>
<h3>{{ the_results }}</h3>
{% endblock %}
需要特别注意双大括号包围的名字就是Jinja2变量,能够从python代码中的相应变量得到值,这里有4个变量:
the_title
the_phrase
the_letters
the_results
但是在vsearch4web.py中的do_search只有与之相对应的2个变量:phrase和letters,所以我们需要再添加对应的the_title和the_results这两个变量,这样一来函数才能够满足呈现这个模板中所需的4个变量
将"Here are your results:"字符串赋给the_title
将search4letters调用赋给the_results
这样一来在呈现模板之前所有4个变量都能作为参数传入模板中
下面再来修改vsearch4web.py
from flask import Flask, render_template, request
from vsearch import search4letters
app = Flask(__name__)
@app.route('/')
def hello() -> str:
return 'Hello world from Flask!'
@app.route('/search4', methods=['POST'])
def do_search() -> 'html': #修改注解,指示这个函数现在返回HTML,而不是像前一个版本返回str(一个纯文本的字符串)
phrase = request.form['phrase']
letters = request.form['letters']
#创建一个python变量,名为title,并为title赋一个字符串
title = 'Here are your results:'
#创建一个python变量,名为results,将“search4letters”的调用结果赋给"results“
results = str(search4letters(phrase, letters))
#results.html模板需要4个参数值,最后的results,这个逗号是可选的,有没有都可以。
#呈现result.html模板,这个模板需要4个参数值
return render_template('results.html',
the_title=title,
the_phrase=phrase,
the_letters=letters,
the_results=results,) #不要忘记这个结束函数调用的结束小括号
#各个python变量赋给相应的Jinja参数,程序代码的数据会传递到模板中
@app.route('/entry')
def entry_page() -> 'html':
return render_template('entry.html',
the_title='Welcome to search4letters on the web!')
app.run(debug=True)
记得保存文件,确保Flask自动地重新加载Web应用
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
entry为生成表单,results为显示结果。添加完4个变量也就是4个参数值后页面已经正常显示了,但是还是需要注意 render_template 调用中最后还包括一个逗号(上图有),不过这在python中是被允许的,是可选的
现在Web应用支持3个URL:/,/search4。/entry。现在不需要"/"url想要同时将hello函数去掉,需要让Flask把对/URL的所有请求重定向到/entry URL,否则当Web浏览器与这个Web应用交互时倘若请求/URL(这是大多数Web应用和网站的默认URL),就会得到一个404"Not Found"错误·。
为此要调整hello函数,让它向所有请求/URL的Web浏览器返回一个HTML redirect,就能够将指向/的请求替换为/entry
修改vsearch4web.py
在from flask导入行上增加rediect
from flask import Flask, render_template, request,redirect #在导入列表中增加redirect
from vsearch import search4letters
app = Flask(__name__)
@app.route('/')
def hello() -> '302': #调整注解,指出该函数将返回什么,300-399范围内的http状态码是重定向,302是调用redirect时Flask向浏览器发回的状态码
return redirect('/entry') #调用Flask的redirect函数,指示浏览器请求另外一个URL(这里变成了/entry)
@app.route('/search4', methods=['POST'])
#修改注解,指示这个函数现在返回HTML,而不是像前一个版本返回str(一个纯文本的字符串)
def do_search() -> 'html':
phrase = request.form['phrase']
letters = request.form['letters']
#创建一个python变量,名为title
title = 'Here are your results:'
#创建一个python变量,名为results,将“search4letters”的调用结果赋给"results“
results = str(search4letters(phrase, letters))
#results.html模板需要4个参数值,最后的results,这个逗号是可选的,有没有都可以。
return render_template('results.html',
the_title=title,
the_phrase=phrase,
the_letters=letters,
the_results=results,)
@app.route('/entry')
def entry_page() -> 'html':
return render_template('entry.html',
the_title='Welcome to search4letters on the web!')
app.run(debug=True)
编辑完成后保存就可以确保Web应用的用户请求/entry或/URL时将看到html表单
在服务器后台可以看到,重定向页面修改后不再返回5000,而是5000/entry了
注意后台返回的302,但是1个请求会变成2个请求,函数是可以有多个URL
“GET /entry HTTP/1.1” 200 - #请求指向/entryURL,可以立即得到服务。200-299范围内的状态码是成功消息:服务器已经接收、理解和处理客户端的请求
“GET / HTTP/1.1” 302 -
“GET /entry HTTP/1.1” 200 - #如果一个请求指向/URL,Web应用首先响应一个302重定向,接着Web浏览器会发送另一个请求指向/entryURL,这会成功地得到Web应用的服务 200状态码
这里的重定向似乎有点浪费,每次指向/URL的一个请求都会变成两个请求,现在需要Flask将多个URL与一个给定的函数关联,就无需重定向了
所以如果一个函数有多个关联的URL,Flask会尝试依次与各个URL匹配,找到一个匹配就会执行这个函数
修改vsearch4web.py
从from flask 导入行删除redirect,因为我们不再需要这个函数
剪切 @app.route('/') 并粘到 @app.route('/entry')的上面,删除hellp函数的两行代码,因为Web不再需要这些代码
from flask import Flask, render_template, request
from vsearch import search4letters
app = Flask(__name__)
@app.route('/search4', methods=['POST'])
def do_search() -> 'html':
phrase = request.form['phrase']
letters = request.form['letters']
title = 'Here are your results:'
results = str(search4letters(phrase, letters))
return render_template('results.html',
the_title=title,
the_phrase=phrase,
the_letters=letters,
the_results=results,)
@app.route('/') #entry_page函数现在有两个关联的URL
@app.route('/entry')
def entry_page() -> 'html':
return render_template('entry.html',
the_title='Welcome to search4letters on the web!')
app.run(debug=True)
上面的run那里前面是没有if的,可以删除,加上回去是为了pythonanywhere
更新了后台后就可以看到只有一个请求一个反应了,奇怪的是我只看到了post,没有看到get一定是哪里有弄错了,但是我把最后一行的if给删掉了也没有变化,其实是我自己理解错了。打开网址是get,是正确的。输入返回是post得到的返回值,所以是一个get一个post
现在访问/URL,会出现html表单,在查看Web应用的状态消息,可以确认现在处理/时只会有一个请求,而不再是有两个请求。输入并且按Do it 就会出现返回的响应。所以到现在就已经完成了Web应用一个请求一个返回状态,可以独立与用户进行交互了
完成到这里需要注意两个点:
@符号标识是一个修饰符。利用修饰符可以改变一个已有函数的行为而无需修改这个函数的代码。在Web应用中,使用Flask的@app.route修饰符为python函数关联URL。一个函数可以修饰多次(do_search函数关联了多个URL)
使用Jinja2文本模板引擎在Web应用中呈现html页面
将Web应用部署到云
在pythonanywhere上面部署我们的Web应用进行托管
pythonanywhere喜欢控制Web应用的启动,认为由它负责调用app.run(),也就是说不再需要在代码中调用app.run()。如果偏要在代码中运行app.run(),pythonanywhere会拒绝运行Web运用
代码最后一行run会与pythonanywhere产生冲突两者不兼容,云只是用来部署而不是用来开发,所以可以用if那一行来开头化解冲突
所以最后一行修改为下面run()
if __name__ == '__main__': #现在只有当直接由python执行时才会运行"app.run()"代码行
app.run(debug=True)
if__name__=='main' 被称为'dunder name dunder main' P239
最终版本
from flask import Flask, render_template, request
from vsearch import search4letters
app = Flask(__name__)
@app.route('/search4', methods=['POST'])
def do_search() -> 'html':
phrase = request.form['phrase']
letters = request.form['letters']
title = 'Here are your results:'
results = str(search4letters(phrase, letters))
return render_template('results.html',
the_title=title,
the_phrase=phrase,
the_letters=letters,
the_results=results,)
@app.route('/')
@app.route('/entry')
def entry_page() -> 'html':
return render_template('entry.html',
the_title='Welcome to search4letters on the web!')
if __name__ == '__main__':
app.run(debug=True)
处理好后,接下来就可以直接部署在云上面了,使用pythonanywhere
到现在需要准备好想要部署在云端的文件夹,并命名为webapp,文件夹包括了vsearch4web.py、在static文件夹中的hf.py,在templates文件夹中的base.html、entry.html和results.html,webapp文件夹中中一共包括了5个文件,这样子才是准备好的。接着把webapp压缩成zip文件而不是rar文件,因为需要用到命令行
出现了一些问题,在按步骤弄好后就可以使用命令行来处理
因为我们已经有了vsearch.py在webapp.zip中了就不需要再去弄vsearch.py的压缩包,直接跳出书本中的第一步
在主界面
将文件上传云
找到Files中的Upload a file 上传压缩文件
但是我之前压缩错了导致后面用命令行解压不出来,记得一定是zip文件其他的都不行
open bash是打开命令行的控制台,我压缩错误没办法解压只能够重新压缩一遍
输入命令行upzip 解压缩找不到文件一直提示我错误,我重新又试了好几遍但是结果显示的错误都是一样的,我定睛一看,是命令行输入错误!
先是 unzip webapp.zip
不是upzip 因为看错我做了一个早上在循环简直在浪费时间。代码一定要细心看,别马大哈
在单击页面右上角的Open a bash console here 链接,打开终端窗口(基于浏览器的Linux控制台-命令提示窗口)来解压缩和安装
先来解压缩(解开web应用代码),使用命令行
unzip webapp.zip
安装Web应用代码,将它安装到mysite文件夹中(我们可以先在仪表板建好mysite文件夹也可以现在退出命令行操作新建文件夹,命令行会一直在后台开着如果你不结束的话)
把代码移至mysite文件夹,使用命令行
mv webapp/* mysite
弄好了mv后返回仪表板选择web标签页,只能创建一个web项目,但是要想创建两个以上应用必须要付费。单击"Add a new web app"来创建应用
建好后千万不要按绿色大按钮,因为我们还没有告诉pythonanywhere代码是多少,暂时不要运行
往下翻页找到Code下面的WSGI configuration file 标签右边的长链接,其它所有代码行都不理,单击这个长连接链接,这个长连接会把你新创建的Flask web 应用的配置文件加载到pythonanywhere的web文本编辑器中,它和上文中提及的run()调用密切相关。
pythonanywhere会在调用app.run()之前导入web应用的代码,是因为这个配置文件支持了这种行为。但是要让它引用我们的代码就需要来编辑修改这个文件的最后一行:
将原文件的 from flask_app import app as application 修改为
from vsearch4web import app as application
修改这个文件最后一行是为了能够引用vsearch4web模块
也就是可以说 从......当中导进来作为app的应用
这里的......就是vsearch4web.py
修改完成配置文件后,记得保存Save
接着就可以点击绿色大按钮了,并且点击网址就可以跳转到网页上,云部署已经成功了。网页会显示正常,现在的网页不仅仅能够在本地运行,任何人只要连入互联网并且有一个Web浏览器就可以使用这个应用
任何人都可以通过使用这个Web地址与Web应用进行交互
现在要返回仪表板并且进行注销,注意,尽管你已经注销,但是Web应用还会在云中继续运行,除非告诉它停止运行