Flask-1-03-HelloWorld

Flask程序运行过程:

全部Flask程序必须有一个程序实例html

Flask调用视图函数后,会将视图函数的返回值做为响应的内容,返回给客户端。通常状况下,响应内容主要是字符串和状态码。python

当客户端想要获取资源时,通常会经过浏览器发起HTTP请求。此时,Web服务器使用WSGI(Web Server Gateway Interface)协议,把来自客户端的全部请求都交给Flask程序实例。WSGI是为 Python 语言定义的Web服务器和Web应用程序之间的一种简单而通用的接口,它封装了接受HTTP请求、解析HTTP请求、发送HTTP,响应等等的这些底层的代码和操做,使开发者能够高效的编写Web应用。正则表达式

程序实例使用Werkzeug来作路由分发(URL请求和视图函数之间的对应关系)。根据每一个URL请求,找到具体的视图函数。 在Flask程序中,路由的实现通常是经过程序实例的route装饰器实现。route装饰器内部会调用add_url_route()方法实现路由注册。flask

调用视图函数,获取响应数据后,把数据传入HTML模板文件中,模板引擎负责渲染响应数据,而后由Flask返回响应数据给浏览器,最后浏览器处理返回的结果显示给客户端。浏览器

 

了解一门框架从HelloWorld开始


 

新建文件helloworld.py:

# 导入Flask类
from flask import Flask

#Flask类接收一个参数__name__
app = Flask(__name__)

# 装饰器的做用是将路由映射到视图函数index
@app.route('/')
def index():
    return 'Hello World'

# Flask应用程序实例的run方法启动WEB服务器
if __name__ == '__main__':
    app.run()

这些就已经足够了,那么咱们来运行一下helloworld.py(到保存helloworld.py的路径下):

$ cd /home/python/code
$ python helloworld.py

可以看出服务器已经启动,地址是127.0.0.1 端口:5000,这时候去浏览器访问查看结果

初始化参数:

  1. import_name: 模块名,flask以这个模块所在的目录为总目录,默认这个目录中的static为静态目录,templates为模板目录
  2. static_url_path:访问静态资源的url前缀, 默认值是static
  3. static_folder: 默认‘static’ 静态文件的目录
  4. template_folder: 默认‘templates’ 模板文件的目录
...

app = Flask(__name__,
            static_url_path="/python",  # 访问静态资源的url前缀, 默认值是static
            static_folder="static",  # 静态文件的目录,默认就是static
            template_folder="templates",  # 模板文件的目录,默认是templates
            )

...

配置参数

配置参数默认有3中方式:

  • app.config.from_pyfile(“config.cfg”)   从文件导入
  • app.config.from_object()  从对象中导入服务器

  • app.config.from_envvar()  从环境变量中导入(应该没有人愿意用)

1. app.config.from_pyfile(“config.cfg”) :在项目的根目录下建立一个config.cfg文件

 1 from flask import Flask
 2 
 3 app = Flask(__name__,
 4             static_url_path="/python",  # 访问静态资源的url前缀, 默认值是static
 5             static_folder="static",  # 静态文件的目录,默认就是static
 6             template_folder="templates",  # 模板文件的目录,默认是templates
 7             )
 8 
 9 # 配置参数的使用方式
10 # 1. 使用配置文件
11 app.config.from_pyfile("config.cfg")
12 
13 
14 @app.route("/")
15 def index():
16     """定义的视图函数"""
17     return "helloworld"
18 
19 
20 if __name__ == '__main__':
21     # 启动flask程序
22     app.run()
# config.cfg 文件
DEBUG = True

目录结构

这样你从新运行一下app

2.app.config.from_object()  从对象中导入

  建立一个类,来定义类属性为配置项框架

# coding:utf-8

from flask import Flask

app = Flask(__name__,
            static_url_path="/python",  # 访问静态资源的url前缀, 默认值是static
            static_folder="static",  # 静态文件的目录,默认就是static
            template_folder="templates",  # 模板文件的目录,默认是templates
            )

# 2. 使用对象配置参数
class Config(object):
    DEBUG = True
# 使用方法加载设置的配置
app.config.from_object(Config)


@app.route("/")
def index():
    """定义的视图函数"""
    return "hello world"


if __name__ == '__main__':
    # 启动flask程序
    app.run()

3.直接操做config对象

from flask import Flask

app = Flask(__name__,
            static_url_path="/python",  # 访问静态资源的url前缀, 默认值是static
            static_folder="static",  # 静态文件的目录,默认就是static
            template_folder="templates",  # 模板文件的目录,默认是templates
            )

# 3. 直接操做config的字典对象
app.config["DEBUG"] = True


@app.route("/")
def index():
    return "hello flask"


if __name__ == '__main__':
    # 启动flask程序
    app.run()
   

读取配置参数

  1.若是你在当前能访问到app的状况下函数

    app.config.get("DEBUG")post

  2.若是你没法拿到app这个对象时,你只须要导入current_app,也是能够拿到配置信息的

    current_app.config.get("DEBUG")

from flask import Flask, current_app

@app.route("/")
def index():
    """定义的视图函数"""
    # 读取配置参数
    # 1. 直接从全局对象app的config字典中取值
    # print(app.config.get("ITCAST"))
    # 2. 经过current_app获取参数
    # print(current_app.config.get("ITCAST"))

    return "hello flask"

app.run 参数

if __name__ == '__main__':
    # 启动flask程序
    # app.run()
    app.run(host="0.0.0.0", port=5000, debug=True) # port指定的端口,debug 是惟一能够指定在这里的配置项

你在开发的状态下,若是局域网中不须要别的主机访问,你能够不指定(host),若是你想在同一局域网中,别的主机也能够访问到,而且你本身还想以回环地址(127.0.0.1)访问的话就能够指定为‘0.0.0.0’

扩展: 0.0.0.0  

IPV4中,0.0.0.0地址被用于表示一个无效的,未知的或者不可用的目标。 
* 在服务器中,0.0.0.0指的是本机上的全部IPV4地址,若是一个主机有两个IP地址,192.168.1.1 和 10.1.2.1,而且该主机上的一个服务监听的地址是0.0.0.0,那么经过两个ip地址都可以访问该服务。 
* 在路由中,0.0.0.0表示的是默认路由,即当路由表中没有找到彻底匹配的路由的时候所对应的路由。

用途总结:

    • 当一台主机尚未被分配一个IP地址的时候,用于表示主机自己。(DHCP分配IP地址的时候)
    • 用做默认路由,表示”任意IPV4主机”。
    • 用做服务端,表示本机上的任意IPV4地址。

如今页面基本是能够展现了,定义url的规则咱们是经过装饰器来添加 [ @app.route() ],那么若是我有不少的页面,我想直观的查看一下具体都定义了哪些,咱们这里就能够经过:app.url_map 来查看

from flask import Flask, current_app

app = Flask(__name__,
            static_url_path="/python",  # 访问静态资源的url前缀, 默认值是static
            static_folder="static",  # 静态文件的目录,默认就是static
            template_folder="templates",  # 模板文件的目录,默认是templates
            )

class Config(object):
    DEBUG = True

app.config.from_object(Config)


@app.route("/")
def index():
    """定义的视图函数"""
    return "hello flask"


if __name__ == '__main__':
    # 启动flask程序
    print(app.url_map) # 打印路由的详情
    app.run()
    

返回结果

(Flask_py) python@python-VirtualBox:~/code$ python hello.py 
# 首先'/' 是咱们index定义的路由规则
# (HEAD, OPTIONS, GET)能够经过元组中这三种方式访问
# index是指定的视图函数
Map([<Rule '/' (HEAD, OPTIONS, GET) -> index>,  
# /python/<filename> 这是访问静态页面的路由规则
# (HEAD, OPTIONS, GET)默认的访问方式
# static 静态资源
 <Rule '/python/<filename>' (HEAD, OPTIONS, GET) -> static>])  
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat

这里咱们也能够经过访问方式来作一些限制性的功能:

好比指定一个视图,只能经过post方式请求

这里咱们定义一个视图 指定访问方式为POST

...

@app.route('/post_only', methods=['POST']) def post_only(): return 'post method page'
...

返回结果:这里能够看出爆了一个405的状态码。DEBUG给咱们爆出的错误是GET这种请求方式是不容许的

这里咱们将GET请求方式也添加到列表中,查看一下是否能够访问

...

@app.route('/post_only', methods=['GET','post']) def post_only(): return 'post method page'
...

经过返回的结果能够看出,已经能够访问,而且返回了咱们的响应信息

经过请求方式,咱们能够的到一些限制,那么咱们若是定义一样的路由规则,它又会有怎样的功能呢?

首先以相同的路径相同的访问方式咱们来查看一下会产生什么样的结果

# 这里咱们有两个视图分别为hello一、hello2
@app.route('/hello')
def hello1():
    return 'This is a hello 1'

@app.route('/hello')
def hello2():
    return 'This is a hello 2'

返回结果:页面展现咱们能够看出hello2这个视图函数并无执行,可是经过【app.url_map】咱们能够看出两个视图都在集合当中。

 <Rule '/hello' (HEAD, OPTIONS, GET) -> hello1>,
 <Rule '/hello' (HEAD, OPTIONS, GET) -> hello2>,

很明显,它们两个路径规则和访问方式,都是相同的,因此当匹配到第一个的时候,就不会在往下执行,那么接下来,咱们给hello1指定POST请求方式,hello2指定GET请求方式,会返回怎样的结果呢?

# 这里咱们分别给hello一、hello2设置了请求方式
@app.route('/hello', methods=['POST'])
def hello1():
    return 'This is a hello 1'

@app.route('/hello', methods=['GET'])
def hello2():
    return 'This is a hello 2'

返回结果:

虽然访问的路径是相同的,可是请求方式的不一样,也是能够帮咱们限制想要访问的视图

 这里两个函数用了一个路径,反之一个函数使用两个路径那么也应该是能够的

# 定义了一个视图为test
@app.route('/test1')
@app.route('/test2')
def test():
    return 'two routes are used for one page'

经过返回结果能够看出,返回的是同一个页面

在路径当中重定向是很是常见的事情,这里咱们也简单的介绍一下

这里就用到redirect()

# 导入redirect来实现页面重定向
from flask import Flask, current_app, redirect 

...

@app.route("/")
def index():
    """定义的视图函数"""
    return "index page"

# 建立一个login视图,当执行完毕后直接返回到index页面
@app.route('/login')
def login():
    # 定义index视图的路径
    url = '/'
    return redirect(url)    
...

返回结果:访问127.0.0.1:5000/login页面

 这里有一个隐患在里面,若是有一天,咱们认为index视图的路径 '/' 不太适合了,想更改成'/index',那么项目里全部跳转到index的页面就须要所有改变,这样就会给咱们程序带来隐患,那么咱们找到一个能够反向解析的方法,只要这个视图函数还在,无论改变什么路径,咱们后续跳转页面都不须要更改,那么就须要使用 url_for('须要跳转的函数名') 

# 优化代码,使用反向解析来实现跳转到 index 页面
from flask import Flask, current_app, redirect, url_for
...

@app.route("/")  # 当这里路径更改以后,下面login视图中的地址也不须要改变
def index():
    return "index page"

@app.route('/login')
def login():
    url = url_for('index')
    return redirect(url)
...

返回结果:

以前咱们一直都是用写死的方式,来定义路由规则,这确定是不能知足咱们的开发需求:

如何动态的设置一个路由规则呢?

转换器:Flask默认给咱们指定了3种,使用方法以下:

int 接受整数
float 接收浮点数
path 和默认的相同,但也接受斜线
# 这里指定int,尖括号中冒号后面的内容是动态的
@app.route('/user/<int:id>')
def user(id):
    return '欢迎id: %d的用户' %id

 

这里若是不指定类型,路由传递的参数默认当作string处理

# 127.0.0.1:5000/user/hannibal
@app.route('/user/<username>')
def user(username):
    return '欢迎 %s ' %username

 返回结果:

若是这里爆出:UnicodeDecodeError: 'ascii' codec can't decode byte 0xe6 in position 0: ordinal not in range(128). 点击这里

即便是拥有了int、float、string 这些也是不能知足咱们的需求,那么咱们就须要自定义转换器,大致的流程是,咱们须要定义一个类来自定义咱们的转换器,这个类咱们能够随便起名,这里就用RegexConverter(很是重要的一点是这个类须要继承werkzeug.routing中的BaseConverter这个类),接下来须要将自定义的转换器添加到Flask的应用中。最后就是函数来使用这个自定义的转换器,举个栗子:

from flask import Flask, current_app, redirect, url_for
from werkzeug.routing import BaseConverter  # 咱们须要继承的转换器类
app = Flask(__name__)

class RegexConverter(BaseConverter):
    """自定义转换器类"""
    def __init__(self, url_map, regex):
        # 调用父类的初始化方法 这里咱们须要将url_map传给父类
        super(RegexConverter, self).__init__(url_map)
        # 将正则表达式的参数保存到对象的属性中,flask会去使用这个属性来进行路由的正则匹配
        self.regex = regex  # 这个就是咱们规定的正则匹配的规则 r'1[34578]\d{9}' self.regex是固定的写法

# 将自定义的转换器添加到flask的应用中 
# 这里咱们向converters这个字典中添加了一个re键对应咱们的转换器,re本身能够随便命名
app.url_map.converters['re'] = RegexConverter # 这里模拟匹配手机号码 # 127.0.0.1:5000/send/138XXXXXXXX @app.route("/send/<re(r'1[34578]\d{9}'):phone_num>") def send_sms(phone_num): return "send message to %s" % phone_num if __name__ == '__main__': # 查看路由信息 print(app.url_map) # 启动flask程序 app.run(debug=True)

返回结果:这里若是你填写一个不匹配的手机号,就必定会报错,那么说明你自定义的转换器就生效了

这里你也能够从新建立一个视图好比匹配邮箱,调用你的自定义转换器类,而且传入正则规则,也是可使用的,固然自定义的转换器还有两个方法也是值得一提的:

1.to_python(self, value):当请求的url中包含的参数经过正则验证以后,会经过to_python这个方法返回给对应的视图

举个栗子:需求隐藏手机号的后四位替换成xxxx

from flask import Flask
from werkzeug.routing import BaseConverter
app = Flask(__name__)


class RegexConverter(BaseConverter):
    """自定义转换器类"""
    def __init__(self, url_map, regex):
        # 调用父类的初始化方法 这里咱们须要的第二个参数就是传给父类
        super(RegexConverter, self).__init__(url_map)
        # 将正则表达式的参数保存到对象的属性中,flask会去使用这个属性来进行路由的正则匹配
        print('init 执行了')
        self.regex = regex 
        # 定义一个实例属性存储原手机号和加密后的手机号
        self.phone = []

    def to_python(self, value):
        print('to_python 执行了')
        # 将原有的手机号码存入集合中
        self.phone.append(value) 
        # 自制加密
        self.value = value[0:8] + "XXXX"
        # 将加密的数据存入集合中
        self.phone.append(self.value)
        return self.phone

# 将自定义的转换器添加到flask的应用中
app.url_map.converters['re'] = RegexConverter

# 这里模拟匹配手机号码
# 127.0.0.1:5000/send/138XXXXXXXX
@app.route("/send/<re(r'1[34578]\d{9}'):phone_num>")
def send_sms(phone_num):
    original_number = phone_num[0]
    encrypted_data = phone_num[1]
    return "%s send message to %s" % (original_number, encrypted_data)

if __name__ == '__main__':
    # 查看路由信息
    print(app.url_map)
    # 启动flask程序
    app.run(debug=True)
    

返回结果:

若是传入的参数没法匹配正则就不会去执行to_python,若是没有重写to_python方法,默认会调用父类的to_python方法,而后将返回值给调用的视图函数:ps:在文档中为了避免显得冗长,我删除了一个没用的视图,可是执行时候还在那因此这里会有两个视图

2.to_url(self, value):当使用到url_for的时候使用到

大体流程:定义了一个index函数用于跳转到send_sms中,这里index视图函数使用url_for 因此会调用to_url方法,首先访问127.0.0.1:5000/ 会跳转到send_sms

from flask import Flask, current_app, redirect, url_for
from werkzeug.routing import BaseConverter
app = Flask(__name__)


class RegexConverter(BaseConverter):
    """自定义转换器类"""
    def __init__(self, url_map, regex):
        # 调用父类的初始化方法 这里咱们须要的第二个参数就是传给父类
        super(RegexConverter, self).__init__(url_map)
        # 将正则表达式的参数保存到对象的属性中,flask会去使用这个属性来进行路由的正则匹配
        print('init 执行了')
        self.regex = regex 
        self.phone = []

    def to_python(self, value):
        print('to_python 执行了')
        self.phone.append(value) 
        self.value = value[0:8] + "XXXX"
        self.phone.append(self.value)
        return self.phone

    def to_url(self, value):
        print('to_url 执行了')
        return value

# 将自定义的转换器添加到flask的应用中
app.url_map.converters['re'] = RegexConverter

# 这里模拟匹配手机号码
# 127.0.0.1:5000/send/138XXXXXXXX
@app.route("/send/<re(r'1[34578]\d{9}'):phone_num>")
def send_sms(phone_num):
    print('send_sms 视图函数执行')
    original_number = phone_num[0]
    encrypted_data = phone_num[1]
    return "%s send message to %s" % (original_number, encrypted_data)


@app.route('/')
def index():
    # 使用反向解析到咱们定义的send_sms视图函数
    # 由于路径匹配规则中有phone_num 因此这里咱们须要传参
    print('index')
    url = url_for('send_sms', phone_num='18000000000')
    return redirect(url)


if __name__ == '__main__':
    # 查看路由信息
    print(app.url_map)
    # 启动flask程序
    app.run(debug=True)

返回结果:访问127.0.0.1:5000/

后台查看一下执行流程:

相关文章
相关标签/搜索
本站公众号
   欢迎关注本站公众号,获取更多信息