返回顶部

Flask基础

初识Flask

Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于接收http请求并对请求进行预处理,然后触发Flask框架,开发人员基于Flask框架提供的功能对请求进行相应的处理,并返回给用户,如果要返回给用户复杂的内容时,需要借助jinja2模板来实现对模板的处理,即:将模板和数据进行渲染,将渲染后的字符串返回给用户浏览器。

下载:

pip3 install flask

当前版本:1.1.2

from werkzeug.wrappers import Request, Response

@Request.application
def hello(request):
    return Response('Hello World!')

if __name__ == '__main__':
    from werkzeug.serving import run_simple
    run_simple('localhost', 4000, hello)

基本使用

一.FlaskDemo

from flask import Flask

# 实例化一个Flask对象 给它指定一个名字
app = Flask(__name__)

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

if __name__ == '__main__':
    app.run()

二.配置文件

我们可以在实例化Flask对象之后~打印一下app.config来查看Flask的配置信息。

我们也可以通过app.config.xxx = xxx来更改配置信息,但是通常我们不这样去做~~

配置文件的实现方式:

 

先看一个应用小Demo

from flask import Flask

app = Flask(__name__)
app.config.from_object('settings.DevelopmentConfig')


@app.route('/index', methods=['GET', 'POST'])
def index():
return 'hello world'


if __name__ == '__main__':
app.run()

settings.py:

class BaseConfig(object):
    DEBUG = True

    SECRET_KEY = 'MAOMAO1019'


class ProductionConfig(BaseConfig):
    DEBUG = False

class DevelopmentConfig(BaseConfig):
    pass

class TestingConfig(BaseConfig):
    pass
flask中的配置文件是一个flask.config.Config对象(继承字典),默认配置为:
    {
        'DEBUG':                                get_debug_flag(default=False),  是否开启Debug模式
        'TESTING':                              False,                          是否开启测试模式
        'PROPAGATE_EXCEPTIONS':                 None,                          
        'PRESERVE_CONTEXT_ON_EXCEPTION':        None,
        'SECRET_KEY':                           None,                           开启session前需设置
        'PERMANENT_SESSION_LIFETIME':           timedelta(days=31),
        'USE_X_SENDFILE':                       False,
        'LOGGER_NAME':                          None,
        'LOGGER_HANDLER_POLICY':               'always',
        'SERVER_NAME':                          None,
        'APPLICATION_ROOT':                     None,
        'SESSION_COOKIE_NAME':                  'session',
        'SESSION_COOKIE_DOMAIN':                None,
        'SESSION_COOKIE_PATH':                  None,
        'SESSION_COOKIE_HTTPONLY':              True,
        'SESSION_COOKIE_SECURE':                False,
        'SESSION_REFRESH_EACH_REQUEST':         True,
        'MAX_CONTENT_LENGTH':                   None,
        'SEND_FILE_MAX_AGE_DEFAULT':            timedelta(hours=12),
        'TRAP_BAD_REQUEST_ERRORS':              False,
        'TRAP_HTTP_EXCEPTIONS':                 False,
        'EXPLAIN_TEMPLATE_LOADING':             False,
        'PREFERRED_URL_SCHEME':                 'http',
        'JSON_AS_ASCII':                        True,
        'JSON_SORT_KEYS':                       True,
        'JSONIFY_PRETTYPRINT_REGULAR':          True,
        'JSONIFY_MIMETYPE':                     'application/json',
        'TEMPLATES_AUTO_RELOAD':                None,
    }

 

三.路由系统

@app.route('/user/<username>')
@app.route('/post/<int:post_id>')
@app.route('/post/<float:post_id>')
@app.route('/post/<path:path>')

# 路由默认支持的参数
DEFAULT_CONVERTERS = {
    'default':          UnicodeConverter,
    'string':           UnicodeConverter,
    'any':              AnyConverter,
    'path':             PathConverter,
    'int':              IntegerConverter,
    'float':            FloatConverter,
    'uuid':             UUIDConverter,
}

注意:直接<username>,就代表接收一个字符串类型的参数。

路由的几种写法:

def index():
  return "Index"

self.add_url_rule(rule='/index', endpoint="index", view_func=index, methods=["GET","POST"]
# 或者这样 app.add_url_rule(rule='/index', endpoint="index", view_func=index, methods=["GET","POST"])
app.view_functions[
'index'] = index

#还可以这样:
def auth(func):
   def inner(*args, **kwargs):
         print('before')
         result = func(*args, **kwargs)
         print('after')
         return result
   return inner

class IndexView(views.View):
   methods = ['GET']
   decorators = [auth, ]

  def dispatch_request(self):
     print('Index')
     return 'Index!'

app.add_url_rule('/index', view_func=IndexView.as_view(name='index'))  # name=endpoint

其实,app.route()是通过装饰器,去执行add_url_rule(rule, endpoint, f, **options)这个方法。
@app.route和app.add_url_rule参数:
            rule,                       URL规则
            view_func,                  视图函数名称
            defaults=None,              默认值,当URL中无参数,函数需要参数时,使用defaults={'k':'v'}为函数提供参数
            endpoint=None,              名称,用于反向生成URL,即: url_for('名称')
            methods=None,               允许的请求方式,如:["GET","POST"]
            

            strict_slashes=None,        对URL最后的 / 符号是否严格要求,
                                        如:
                                            @app.route('/index',strict_slashes=False),
                                                访问 http://www.xx.com/index/ 或 http://www.xx.com/index均可
                                            @app.route('/index',strict_slashes=True)
                                                仅访问 http://www.xx.com/index 
            redirect_to=None,           重定向到指定地址
                                        如:
                                            @app.route('/index/<int:nid>', redirect_to='/home/<nid>')
                                            或
                                            def func(adapter, nid):
                                                return "/home/888"
                                            @app.route('/index/<int:nid>', redirect_to=func)
            subdomain=None,             子域名访问
                                                from flask import Flask, views, url_for

                                                app = Flask(import_name=__name__)
                                                app.config['SERVER_NAME'] = 'wupeiqi.com:5000'


                                                @app.route("/", subdomain="admin")
                                                def static_index():
                                                    """Flask supports static subdomains
                                                    This is available at static.your-domain.tld"""
                                                    return "static.your-domain.tld"


                                                @app.route("/dynamic", subdomain="<username>")
                                                def username_index(username):
                                                    """Dynamic subdomains are also supported
                                                    Try going to user1.your-domain.tld/dynamic"""
                                                    return username + ".your-domain.tld"


                                                if __name__ == '__main__':
                                                    app.run()

除了flask给我们提供的正则路由匹配规则外,还可以自定义匹配规:

from flask import Flask, url_for
from werkzeug.routing import BaseConverter

app = Flask(__name__)
app.config.from_object('settings.DevelopmentConfig')


class RegexConverter(BaseConverter):
    """
    自定义URL匹配正则表达式
    """

    def __init__(self, map, regex):
        super(RegexConverter, self).__init__(map)
        self.regex = regex

    def to_python(self, value):
        """
        路由匹配时,匹配成功后传递给视图函数中参数的值
        :param value:
        :return:
        """
        return int(value)

    def to_url(self, value):
        """
        使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数
        :param value:
        :return:
        """
        val = super(RegexConverter, self).to_url(value)
        return val

# 添加到flask中
app.url_map.converters['regex'] = RegexConverter

@app.route('/index/<regex("\d+"):nid>', methods=['GET', 'POST'],endpoint='index')
def index(nid):
    print(nid)
    print(type(nid))  # <class 'int'>
    print(url_for('index'))  # /index/1
    return 'hello 123'


if __name__ == '__main__':
    app.run()

 四.模板

Flask使用的是Jinja2模板,所以其语法和Django无差别

Flask中自定义模板方法的方式和Bottle相似,创建一个函数并通过参数的形式传入render_template:

from flask import Flask, render_template, Markup

app = Flask(__name__)
app.config.from_object('settings.DevelopmentConfig')

# 这是一个全局的模板函数,可以在该APP下的所有函数中使用,注意:Markup等价django的mark_safe
@app.template_global()
def get_input(value):
    return Markup('<input type="%s">' % value)


@app.route('/index', methods=['GET', 'POST'])
def index():
    context = {
        "k1": 123,
        "k2": [11, 22, 33],
        "k3": {"name": "oldboy", "age": 84},
        "k4": lambda x: x + 1,
    }

    return render_template('index.html', **context)


if __name__ == '__main__':
    app.run()

对应的index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>{{ k1 }}</h1>
    <h2>{{ k2[1] }},{{ k2.2 }}</h2>
    <h3>{{ k3.name }},{{ k3['name']}}, {{ k3.get('age', 888) }}</h3>
    <h3>{{ k4(1) }}</h3>
    <h3>{{ get_input('input') }}</h3>
</body>
</html>

五.请求和响应

常用的请求方法:

# 请求相关信息
    # request.method
    # request.args
    # request.form
    # request.cookies
    # request.headers
    # request.path
    # request.files
    # obj = request.files['the_file_name']
    # obj.save('/var/www/uploads/' + secure_filename(obj.filename))
    # request.url
    # request.base_url
    # request.url_root
    # request.host_url
    # request.host

    # obj = request.files['the_file_name']
    # obj.save('/var/www/uploads/' + secure_filename(f.filename))

常用的请求方法:

# 响应相关
    # return 'hello world'
    # return template_rendered('index.html', n=123)
    # return jsonify({"name":"maomao"})

# 设置响应头
    # response = make_response(render_template('index.html'))
    # response.set_cookie('key', 'value')
    # response.headers['X-Something'] = 'A value'
    # response.delete_cookie('key')
    # return response

    # response是flask.wrappers.Response类型

六.session

除了请求对象外,还有一个session对象,它允许你在不同请求间存储特定用户的信息。

它是在 Cookies 的基础上实现的,并且对 Cookies 进行加密,你需要设置一个密钥。

设置session:

session['xxxxxx'] = 'xxx'

删除session:

session.pop('xxxx', None)

基本使用:

from flask import Flask, session, redirect, url_for, escape, request
 
app = Flask(__name__)
app.secret_key = 'qwer666'
 
@app.route('/')
def index():
    if 'username' in session:
        return "已经登录"
    return "未登录"
 
@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        session['username'] = request.form['username']
        return redirect(url_for('index'))
    return render_template('login.html'i)
 
@app.route('/logout')
def logout():
    session.pop('username', None)
    return redirect(url_for('index'))

 

七.特殊的装饰器

先回顾一下装饰器:

import functools


def wrapper(func):
    @functools.wraps(func)
    def inner(*args, **kwargs):
        ret = func(*args, **kwargs)
        return ret

    return inner


"""
1.执行wrapper函数,并将被装饰的函数当成参数。 wrapper(index)
2.将第一步的返回值,赋新值给index:   新index = wrapper(老index)
"""


@wrapper
def index(a1):
    return a1 + 100


@wrapper
def order(a1):
    return a1 + 100


print(index(200))
print(index.__name__)
print(order.__name__)

flask给我们提供的装饰器,有点像Django中的中间件:before_request, after_request

from flask import Flask

app = Flask(__name__)
app.config.from_object('settings.DevelopmentConfig')

@app.before_request
def xxx1():
    print('执行前1')

@app.before_request
def xxx2():
    print('执行前2')


@app.after_request
def ooo1(response):
    print('执行后1')
    return response

@app.after_request
def ooo2(response):
    print('执行后2')
    return response

@app.route('/x1', methods=['GET', 'POST'])
def x1():
    print('视图函数1')
    return 'hello x1'


@app.route('/x2', methods=['GET', 'POST'])
def x2():
    print('视图函数2')
    return 'hello x2'



if __name__ == '__main__':
    app.run()

我们访问http://127.0.0.1:5000/x1,打印出来的结果应该是:

执行前1
执行前2
视图函数1
执行后2
执行后1

其他的装饰器:

@app.template_global()
@app.template_filter()
@app.before_firse_request
@app.errorhandler(404)

通过before_request,在验证用户登录的时候,就不用在很多视图函数都用session去判断了:

@app.before_request
def auth2():
    if request.path == "/login":
        return None
    if session.get("userinfo"):
        return None
    return redirect("/login")

八.蓝图

我们写正式的项目时,可以通过蓝图,建立一个规范的目录结构。

蓝图的三大作用:

  划分规范的目录结构

  对URL进行划分

  给某一个蓝图app加before_request

使用方法:

生成蓝图对象:

from flask imort Blueprint

userBlue = Blueprint("userBlue", __name__)

@userBlue.route("/user")
def user():
    return "USER"

注册蓝图对象:

from .view.user import userBlue
from flask import Flask


def create_app():
    app = Flask(__name)

    app.register_blueprint(userBlue)
    return app

下面是一个小的Demo:

 account.py:


from flask import Blueprint,render_template

ac = Blueprint('ac',__name__, url_prefix='/acc') # url_prefix给url加前缀

@ac.before_request
def bf():

print('before_request')


@ac.route('/login')
def login():

return render_template('login.html')


@ac.route('/logout')
def logout():
return 'logout'
 

admin.py:

from flask import Blueprint

ad = Blueprint('ad',__name__)

@ad.route('/home')
def home():

    return 'home'

user.py:

from flask import Blueprint

us = Blueprint('us',__name__)


@us.route('/info')
def info():

    return 'info'

init.py:

from flask import Flask

app = Flask(__name__)
app.debug = True


from .views import account
from .views import admin
from .views import user


app.register_blueprint(account.ac)
app.register_blueprint(admin.ad)
app.register_blueprint(user.us)

 

九.闪现

Flask 提供了一个非常简单的方法来使用闪现系统(Flash)向用户反馈信息。闪现系统使得在一个请求结束的时候记录一个信息,然后在且仅仅在下一个请求中访问这个数据。

from flask import Flask, session, flash, get_flashed_messages

app = Flask(__name__)
app.config.from_object('settings.DevelopmentConfig')


@app.route('/x1', methods=['GET', 'POST'])
def x1():
    flash('我爱python1')
    # flash('我爱python2',category='x2')

    return 'hello x1'


@app.route('/x2', methods=['GET', 'POST'])
def x2():
    data = get_flashed_messages()
    print(data)
    return 'hello x2'


if __name__ == '__main__':
    app.run()

 

posted @ 2020-10-01 21:32  muguangrui  阅读(129)  评论(0编辑  收藏  举报