Flask学习记录(一)

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)

在这里插入图片描述

配置分离

  1. 首先创建settings.py配置文件

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

路由和视图

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()

第一篇完结

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值