Flask学习记录
使用pycharm创建新项目指定flask,所以pycharm会自动地在虚拟环境venv中pip install flask,如果默认的flask版本不是我们想使用的版本,我们可以使用pip install flask==1.1.2(这里写版本号)
requirements.txt 文件的生成以及使用
requirements.txt一般用来记录当前所使用的所有依赖版本号,环境迁移时常用
(venv)虚拟环境> pip freeze > requirements.txt # 用来生成该文件
pip install -r requirements.txt # 下载对应所有依赖
模板v1.0
from flask import Flask
app = Flask(__name__)
app.config.from_pyfile('settings.py')
@app.route('/')
def index():
return '我是首页'
if __name__ == '__main__':
app.run()
Flask中文文档
mvc和mtv是神马?点击这里查看
第一个示例
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run() # host指定主机名,port指定端口号



from flask import Flask
app = Flask(__name__)# 查看所有配置
print(app.config)
# 修改配置
app.config['ENV'] = 'development' # development开发 production生产 testing测试
app.config['DEBUG'] = True
"""<Config {'ENV': 'production', 'DEBUG': False, 'TESTING': False, 'PROPAGATE_EXCEPTIONS': None, 'PRESERVE_CONTEXT_ON_EXCEPTION': None, 'SECRET_KEY': None, 'PERMANENT_SESSION_LIFETIME': datetime.timedelta(days=31), 'USE_X_SENDFILE': False, 'SERVER_NAME': None, 'APPLICATION_ROOT': '/', 'SESSION_COOKIE_NAME': 'session', 'SESSION_COOKIE_DOMAIN': None, 'SESSION_COOKIE_PATH': None, 'SESSION_COOKIE_HTTPONLY': True, 'SESSION_COOKIE_SECURE': False, 'SESSION_COOKIE_SAMESITE': None, 'SESSION_REFRESH_EACH_REQUEST': True, 'MAX_CONTENT_LENGTH': None, 'SEND_FILE_MAX_AGE_DEFAULT': None, 'TRAP_BAD_REQUEST_ERRORS': None, 'TRAP_HTTP_EXCEPTIONS': False, 'EXPLAIN_TEMPLATE_LOADING': False, 'PREFERRED_URL_SCHEME': 'http', 'JSON_AS_ASCII': True, 'JSON_SORT_KEYS': True, 'JSONIFY_PRETTYPRINT_REGULAR': False, 'JSONIFY_MIMETYPE': 'application/json', 'TEMPLATES_AUTO_RELOAD': None, 'MAX_COOKIE_SIZE': 4093}>"""
@app.route('/')
def hello_world():
return '<h1 style="text-align:center">你好,Flask!</h1>'
if __name__ == '__main__':
# run(host='ip地址', port=端口号, debug=None) # port 一个端口对应一个应用程序
# host 默认只能本机127.0.0.1访问,如果要想统一局域网下都能访问应改成 0.0.0.0 或 ip地址
# debug 默认None, 修改成True开启调试模式,可以实现热加载,不用每次修改都要重启app了
app.run(host='0.0.0.0', port=8080, debug=True)

配置分离
- 首先创建settings.py配置文件

- 使用app.config.from_object(settings)把配置文件导入进来,但记住这种方法要首先import settings, 还有一种方法可以直接使用app.config.from_pyfile('settings.py’) 将配置文件导入

- 此时再次运行可见配置生效

路由和视图
from flask import Flask
app = Flask(__name__)
app.config.from_pyfile('settings.py')
@app.route('/')
def hello():
return 'this is hello page'
""" route源码底层调用的是add_url_rule(),因此我们直接使用这个方法也可行
def route(self, rule: str, **options: t.Any) -> t.Callable:
def decorator(f: t.Callable) -> t.Callable:
endpoint = options.pop("endpoint", None)
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
"""
""" 以下两种写法是等价的
1.. code-block:: python
@app.route("/")
def index():
...
2.. code-block:: python
def index():
...
app.add_url_rule("/", view_func=index)
"""
def index():
return 'this is index page'
# 将路由和视图函数绑定
app.add_url_rule("/index", view_func=index)
if __name__ == '__main__':
app.run()
变量规则
为了给 URL 增加变量的部分,你需要把一些特定的字段标记成 <variable_name>。这些特定的字段将作为参数传入到你的函数中。当然也可以指定一个可选的转换器通过规则< converter:variable_name >将变量值转换为特定的数据类型。
转换器类型

from flask import Flask
app = Flask(__name__)
app.config.from_pyfile('settings.py')
data = {'a': '蚌埠', 'b': '阜阳', 'c': '北京'}
"""
为了给 URL 增加变量的部分,你需要把一些特定的字段标记成 <variable_name>。
这些特定的字段将作为参数传入到你的函数中。当然也可以指定一个可选的转换器通
过规则< converter:variable_name >将变量值转换为特定的数据类型。
"""
@app.route('/')
def index():
return '我是首页'
@app.route('/city/<key>') # 默认为string类型
def get_city(key):
return data.get(key)
@app.route('/add10/<int:num>')
def add_10(num):
return str(num + 10)
# 这里注意The return type must be a string, dict, tuple, Response instance, or WSGI callable.
if __name__ == '__main__':
app.run()
唯一的 URL / 重定向行为
@app.route('/about') # 不带结尾/,若访问时带了/,则会404
def about():
return 'about page'
@app.route('/project/') # 带结尾/,访问时带不带/都会成功,若不带则会进行重定向行为,先请求一次状态码为308,再次返回成功的路径(200)
def project():
return 'project page'
当用户访问页面忘记结尾斜线时,这个行为允许关联的 URL 继续工作,并且与 Apache 和其它的服务器的行为一致,反之则不行,因此在代码的 URL 设置时斜线只可多写不可少写;另外,URL 会保持唯一,有助于避免搜索引擎索引同一个页面两次。
请求和响应
Response对象
from flask import Flask, Response, make_response
import settings
app = Flask(__name__)
app.config.from_object(settings)
@app.route('/')
def index():
return '<h1>index page</h1>'
# return 后面返回一个字符串其实也会做一个response的封装,最终返回的还是Response对象
@app.route('/404')
def not_found():
return 'not found', 404 # 返回一个带有内容和状态码的元组
@app.route('/resp')
def resp():
response = Response('<h1>response object</h1>')
# response 中包含的一些信息
print(response.headers, type(response.headers))
# Content-Type: text/html; charset=utf-8
# Content-Length: 24
#
# <class 'werkzeug.datastructures.Headers'>
print(response.status_code, type(response.status_code)) # 200 <class 'int'>
print(response.status, type(response.status)) # 200 OK <class 'str'>
return response # 返回一个Response对象
# 定制响应头
@app.route('/resp2')
def resp2():
content = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
<style>
h1 {
text-align: center;
}
div {
width: 100%;
height: 100px;
border: 1px solid red;
}
</style>
</head>
<body>
<h1>欢迎进入首页</h1>
<div>
<ul>
<li>hello</li>
<li>hah</li>
<li>youo</li>
</ul>
</div>
</body>
</html>
"""
response = make_response(content) # 返回一个response
# 可以自定义响应头信息
# response.headers['Content-Type'] = 'text/html'
response.headers['mytest'] = 'hhhhh'
return response
"""Response对象 一些默认值
自己的
default_mimetype = "text/html"
json_module = json
父类继承来的
charset = "utf-8"
default_status = 200
max_cookie_size = 4093
"""
if __name__ == '__main__':
app.run()
总结:
- 视图函数应返回一个Response对象,只不过可以以不同的表现形式出现罢了
- 最简单的就是直接返回一个字符串,让flask去帮我们封装成Response对象
- 可以返回一个二元组形式的tuple,元组中第一个元素为内容,第二个表示状态码
- 若想定制响应头,请使用make_response()方法,详情见上面代码
Request对象
request对象是一个全局对象,但不是通常的类型。在Flask的这些全局对象实际上是给定上下文的局部对象的代理。
想象下线程处理的上下文。一个请求传入,web 服务器决定产生一个新线程(或者其它东西,底层对象比线程更有能力处理并发系统)。当 Flask 开始它内部请求处理时,它认定当前线程是活动的上下文并绑定当前的应用和 WSGI 环境到那个上下文(线程)。它以一种智能的方法来实现,以致一个应用可以调用另一个应用而不会中断。
request其中包含了关于请求的一些常见属性,以及方法
@app.route('/index')
def index():
# request对象直接可以使用,下面打印其中一些信息
print(request.headers) # 请求头信息
print("*"*70)
print(request.path) # /index 也就是写的路由
print("*" * 70)
print(request.full_path) # /index?
print("*" * 70)
print(request.base_url) # http://127.0.0.1:5000/index
return '欢迎来到首页'
再进一步理解request对象之前,先理解下render_template()的作用
浏览器发送请求request->路由规则->视图函数->render_template->找到要渲染的网页进行转义->交给视图函数->打包成response对象->返回给浏览器
再来看一段代码
from flask import Flask, request, Response, render_template
app = Flask(__name__)
app.config.from_pyfile('settings.py')
@app.route('/index')
def index():
# request对象直接可以使用,下面打印其中一些信息
print(request.headers) # 请求头信息
print("*"*70)
print(request.path) # /index 也就是写的路由
print("*" * 70)
print(request.full_path) # /index?
print("*" * 70)
print(request.base_url) # http://127.0.0.1:5000/index
return '欢迎来到首页'
@app.route('/register')
def register():
content = render_template('register.html')
"""
render_template 传入一个在templates目录下的网页名,
网页的内容将会被jinja2模板引擎按照一定规则将html页面进行转义,返回字符串形式交给视图函数
那么问题来了,render_templates 为什么会去找templates目录下的而不是其他目录或者当前目录呢?
原因就在于我们创建Flask对象时,只传入了一个参数__name__,而在Flask类的构造函数中的参数是这样的
def __init__(
self,
import_name: str,
static_url_path: t.Optional[str] = None,
static_folder: t.Optional[str] = "static",
static_host: t.Optional[str] = None,
host_matching: bool = False,
subdomain_matching: bool = False,
template_folder: t.Optional[str] = "templates",
instance_path: t.Optional[str] = None,
instance_relative_config: bool = False,
root_path: t.Optional[str] = None,
)
我们可以看到有一个参数叫template_folder,这是一个默认值参数,如果我们不传,它默认为templates,
其中缘由,不言而明
"""
# resp = Response(content)
return content
@app.route('/register2', methods=['GET', 'POST']) # methods参数传入一个列表,表示可以访问该路由的请求方式有哪些,默认为GET
def register2():
"""
表单 get方式 拿到参数使用request.args
print(request.full_path) # /register2?username=123&address=123
print(request.args) # ImmutableMultiDict([('username', '123'), ('address', '123')])
# args 是一个dict类型,其中有我们想要拿到的信息所以我们使用字典相关方法就能拿到了
print(request.args.get('username'), request.args.get('address')) # 123 123
"""
# 下面演示POST方式获取提交的参数,使用request.form
print(request.form) # ImmutableMultiDict([('username', 'lionel'), ('address', 'beijing')])
print(request.form.get('username'), request.form.get('address')) # lionel beijing
return '注册完成'
if __name__ == '__main__':
print(app.url_map) # 路由规则表
'''
Map([<Rule '/register2' (HEAD, POST, OPTIONS, GET) -> register2>,
<Rule '/register' (HEAD, OPTIONS, GET) -> register>,
<Rule '/index' (HEAD, OPTIONS, GET) -> index>,
<Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>])
'''
app.run()
第一篇完结
3603

被折叠的 条评论
为什么被折叠?



