flask基本功能(配置文件,路由,视图函数,请求和响应,模板,session,蓝图,中间件,闪现,常用装饰器)

配置文件

flask中的配置文件是一个flask.config.Config对象(继承字典),默认配置为:
    {
        'DEBUG':                                get_debug_flag(default=False),  是否开启Debug模式
        'TESTING':                              False,                          是否开启测试模式
        'PROPAGATE_EXCEPTIONS':                 None,                          
        'PRESERVE_CONTEXT_ON_EXCEPTION':        None,
        'SECRET_KEY':                           None,
        '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.config['DEBUG'] = True
 
    PS: 由于Config对象本质上是字典,所以还可以使用app.config.update(...)
 
方式二:
    app.config.from_pyfile("python文件名称")
        如:
            settings.py
                DEBUG = True
 
            app.config.from_pyfile("settings.py")
 
    app.config.from_envvar("环境变量名称")
        环境变量的值为python文件名称名称,内部调用from_pyfile方法
 
 
    app.config.from_json("json文件名称")
        JSON文件名称,必须是json格式,因为内部会执行json.loads
 
    app.config.from_mapping({'DEBUG':True})
        字典格式
 
    app.config.from_object("python类或类的路径")
 
        app.config.from_object('pro_flask.settings.TestingConfig')
 
        settings.py
 
            class Config(object):
                DEBUG = False
                TESTING = False
                DATABASE_URI = 'sqlite://:memory:'
 
            class ProductionConfig(Config):
                DATABASE_URI = 'mysql://user@localhost/foo'
 
            class DevelopmentConfig(Config):
                DEBUG = True
 
            class TestingConfig(Config):
                TESTING = True
 
        PS: 从sys.path中已经存在路径开始写
     
 
    PS: settings.py文件默认路径要放在程序root_path目录,如果instance_relative_config为True,则就是instance_path目录

我们常用的方法

复制代码
from flask import Flask,render_template,redirect
app = Flask(__name__)

# 配置文件
app.config.from_object("settings.DevelopmentConfig")


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

    return ""

if __name__ == '__main__':
    app.run()
复制代码

settings

复制代码
class BaseConfig(object):
    DEBUG = True
    SECRET_KEY = "asudflkjdfadjfakdf"


class ProductionConfig(BaseConfig):
    DEBUG = False


class DevelopmentConfig(BaseConfig):
    pass


class TestingConfig(BaseConfig):
    pass
复制代码

settings中可以定义多种配置,我们根据不同的环境使用不同的配置

路由

两种添加路由的方式

复制代码
方式一:
  @app.route('/xxxx')  # @decorator
  def index():
     return "Index"
方式二:
  def index():
     return "Index"
  app.add_url_rule('/xxx', "n1", index)  #n1是别名
复制代码

执行@app.route('/xxx')时,首先执行app.route('/xxx'),这个方法的源码如下

所以decorator=app.route('/index',methods=['GET','POST']),然后再使用@decorator装饰函数,可以看到实际上就是执行了self.add_url_rule(rule, endpoint, f, **options),所以两种添加路由的方式本质是一样的

添加路由关系的本质:将url和视图函数封装成一个Rule对象)添加到Flask的url_map字段中

路由中传参

@app.route('/user/<username>')   #常用的   不加参数的时候默认是字符串形式的
@app.route('/post/<int:post_id>')  #常用的   #指定int,说明是整型的
@app.route('/post/<float:post_id>')
@app.route('/post/<path:path>')
@app.route('/login', methods=['GET', 'POST'])

常用路由系统有以上五种,所有的路由系统都是基于一下对应关系来处理:

复制代码
DEFAULT_CONVERTERS = {
    'default':          UnicodeConverter,
    'string':           UnicodeConverter,
    'any':              AnyConverter,
    'path':             PathConverter,
    'int':              IntegerConverter,
    'float':            FloatConverter,
    'uuid':             UUIDConverter,
}
复制代码

自定义正则匹配路由

复制代码
from flask import Flask, views, url_for
from werkzeug.routing import BaseConverter

app = Flask(import_name=__name__)


            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>')
            def index(nid):
                print(url_for('index', nid='888'))
                return 'Index'


            if __name__ == '__main__':
                app.run()
复制代码

反向生成URL: url_for

endpoint("name")   #别名,相当于django中的name,如果没有定义endpoint,默认为视图函数的函数名

反向解析需要导入:

from flask import Flask, url_for

示例

复制代码
from flask import Flask,render_template,redirect,url_for
app = Flask(__name__)

@app.route('/index',methods=['GET','POST'],endpoint='n1')
def index():
    v1 = url_for('n1')
    v2 = url_for('login')  # 没有定义endpoint默认为视图函数名
    v3 = url_for('logout')
    print(v1,v2,v3)
    return "Index"

@app.route('/login',methods=['GET','POST'])
def login():
    return "login"

@app.route('/logout',methods=['GET','POST'])
def logout():
    return "logout"

if __name__ == '__main__':
    app.run()
复制代码

@app.route和app.add_url_rule参数

 View Code

@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'] = 'haiyan.com:5000'


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

                            #动态生成
@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()
所有的域名都得与IP做一个域名解析:
        如果你想通过域名去访问,有两种解决方式:
          方式一:
            1、租一个域名 haiyan.lalala
            2、租一个公网IP 49.8.5.62
            3、域名解析:
haiyan.com 49.8.5.62
            4、吧代码放在49.8.5.62这个服务器上,程序运行起来
              用户可以通过IP进行访问
          方式二:如果是自己测试用的就可以用这种方式。先在自己本地的文件中找
             C:WindowsSystem32driversetc 找到HOST,修改配置
            然后吧域名修改成自己的本地服务器127.0.0.1
            加上配置:app.config["SERVER_NAME"] = "haiyan.com:5000"

重定向示例

复制代码
from flask import Flask,render_template,redirect
app = Flask(__name__)
 
@app.route('/index',methods=['GET','POST'],redirect_to='/new')
def index():
    return "老功能"
 
@app.route('/new',methods=['GET','POST'])
def new():
    return '新功能'
 
 
if __name__ == '__main__':
    app.run()
复制代码

当用户访问/index时会自动重定向到/new

给多个视图添加装饰器

复制代码
from flask import Flask,render_template,redirect
app = Flask(__name__)
import functools

def wapper(func):
    @functools.wraps(func)
    def inner(*args,**kwargs):
        print('before')
        return func(*args,**kwargs)
    return inner



@app.route('/xxxx',methods=['GET','POST'])
@wapper
def index():
    return "Index"


@app.route('/order',methods=['GET','POST'])
@wapper
def order():
    return "order"

if __name__ == '__main__':
    app.run()
复制代码

首先要注意的是,装饰器要添加在路由下面,还有就是给多个视图添加同一个装饰器时,由于装饰器装饰后就相当于在执行inner函数,如果视图没有定义endpoint那么都会默认使用函数名,也就是inner,这时多个函数都是inner,会报错,所以要使用

@functools.wraps(func)来保留原函数的函数名等信息

视图函数

Flask中的CBV模式

复制代码
方式一:
    @app.route('/index',endpoint='xx')
    def index(nid):
        url_for('xx',nid=123)
        return "Index"

方式二:
    def index(nid):
        url_for('xx',nid=123)
        return "Index"

    app.add_url_rule('/index',index)
复制代码

请求和响应

 View Code

from flask import Flask
from flask import request
from flask import render_template
from flask import redirect
from flask import make_response

app = Flask(__name__)


@app.route('/login.html', methods=['GET', "POST"])
def login():

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

# 响应相关信息
# return "字符串"
# return render_template('html模板路径',**{})
# return redirect('/index.html')

# response = make_response(render_template('index.html'))
# response是flask.wrappers.Response类型
# response.delete_cookie('key')
# response.set_cookie('key', 'value')
# response.headers['X-Something'] = 'A value'
# return response


return "内容"

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

复制代码
from flask import Flask,url_for,request,redirect,render_template,jsonify,make_response
from urllib.parse import urlencode,quote,unquote
app = Flask(__name__)

@app.route('/index',endpoint='xx')
def index():
    from werkzeug.datastructures import ImmutableMultiDict
  =================
    # get_data = request.args
    # get_dict = get_data.to_dict()
    # get_dict['xx'] = '18'
    # url = urlencode(get_dict)
    # print(url)
  ====================
    # print(request.query_string)
    # print(request.args)
  ==========================
    # val = "%E6%8A%8A%E5%87%A0%E4%B8%AA"
    # print(unquote(val))   #吧上面这样的数据转换成中文
    #
    # return "Index"

    # return "Index"
    # return redirect()
    # return render_template()
    # return jsonify(name='alex',age='18')  #相当于JsonResponse
  =======================
    response = make_response('xxxxx')   ##如果是返回更多的值,cookie,headers,或者其他的就可用它
    response.headers['xxx'] = '123123'
    return response


if __name__ == '__main__':
    # app.__call__
    app.run()
复制代码

返回json格式数据

from flask import Flask,render_template,redirect,request,jsonify,make_response

return json.dumps({}) # return jsonify({})

模板

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

自定义方法

复制代码
from flask import Flask,render_template,redirect,request,jsonify,make_response,Markup
app = Flask(__name__)

def gen_input(value):
    # return "<input value='%s'/>" %value
    return Markup("<input value='%s'/>" %value)

@app.route('/x1',methods=['GET','POST'])
def index():
    context = {
        'k1':123,
        'k2': [11,22,33],
        'k3':{'name':'oldboy','age':84},
        'k4': lambda x: x+1,
        'k5': gen_input, # 当前模板才能调用的函数
    }

    return render_template('index.html',**context)
复制代码

当函数返回的是字符串时,为了防止xss攻击,加了验证,所以页面上显示字符串的形式,解决办法,有两种方式

在后端Markup

v5 = Markup("<input type='text' />")

在前端

{{ v4|safe }}

将这些参数传给前端后,前端页面可以采用类似与django的方式渲染

    <h1>{{k1}}</h1>
    <h1>{{k2.0}}  {{k2[0]}} </h1>
    <h1>{{k3.name}}  {{k3['name']}}  {{k3.get('name',888)}}</h1>
    <h1>{{k4(66)}}</h1>
    <h1>{{k5(99)}}</h1>

这里可以看出flask的渲染方式更贴近python,很多python的语法可以使用,执行函数时也不像django,可以自己加括号执行,还可以传参数

写一个函数在所有的页面都使用

template_global和template_filter

复制代码
@app.template_global()
def sb(a1, a2):
    return a1 + a2


@app.template_filter()
def db(a1, a2, a3):
    return a1 + a2 + a3
复制代码

这么定义后在前端所有的页面都能调用这两个函数

调用方式:{{sb(1,2)}} {{ 1|db(2,3)}}

filter方法的第一个参数就是|的值

模板继承:和django的一样,extends

先定义一个母板

复制代码
<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Title</title>
</head>
<body>
    <div >头部</div>
    <div>
        {% block content %} {% endblock %}
    </div>
    <div >底部</div>
</body>
</html>
复制代码

然后继承它

复制代码
{% extends 'layout.html'%}

{% block content %}
    <h1>{{k1}}</h1>
    <h1>{{k2.0}}  {{k2[0]}} </h1>
    <h1>{{k3.name}}  {{k3['name']}}  {{k3.get('name',888)}}</h1>
    <h1>{{k4(66)}}</h1>
    <h1>{{k5(99)}}</h1>
{% endblock%}
复制代码

session

除请求对象之外,还有一个 session 对象。它允许你在不同请求间存储特定用户的信息。它是在 Cookies 的基础上实现的,并且对 Cookies 进行密钥签名要使用会话,你需要设置一个密钥。

  • 设置:session['username'] = 'xxx'

  • 删除:session.pop('username', None)
 View Code

"""
1. 请求刚刚达到
ctx = RequestContext(...)
- request
- session=None
ctx.push()
ctx.session = SecureCookieSessionInterface.open_session

2. 视图函数

3. 请求结束
SecureCookieSessionInterface.save_session()
"""
from flask import Flask,session
app = Flask(__name__)
app.secret_key = 'sadfasdfasdf'

@app.route('/x1')
def index():
# 去ctx中获取session
session['k1'] = 123
session['k2'] = 123
del session['k2']
return "Index"


@app.route('/x2')
def order():
print(session['k1'])
return "Order"

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

# 1. 请求一旦到来
# app.__call__
# app.wsgi_app
# app.open_session

session的操作和字典相同,默认情况下session存在COOKIE中

源码简单剖析,之前我们已经知道在执行app.run时实际上执行的就是run_simple方法,也就是app(),这时会调用Flask类中的__call__方法

这个方法实际上在执行app.wsgi_app

在wsgi_app方法中首先定义了一个ctx,我们看看self.request_context干了什么

可以看到这个方法实际上就是返回了RequestContext类的对象,而ctx就是这个类的对象,那么这个类中都定义了些什么呢

这里首先定义了request,然后也定义了session,所以这个ctx对象包含了request和session,定义request时,又用到了app中的request_class

这其实是一个类,所以request就是这个类的对象

定义玩ctx后又执行了ctx.push方法

在这个方法中定义了self.session,我们来看看self.app.open_session干了什么

这里实际上执行了self.session_interface.open_session,而session_interface又是一个新的类的对象

这里其实执行的是SecureCookieSessionInterface()的open_session方法

 

可以看到在这个方法中首先从cookies中获取session,如果是第一次访问,取不到val,则直接返回self.session_class(),如果有值,则将值反序列化,再返回self.session_class(data),我们再看看self.session_class做了什么

我们发现这又是一个类,所以上面返回的是这个类的对象

这个类继承了CallbackDict,而CallbackDict又继承了dict

所以我们知道了self.session_class返回的对象其实是一个特殊的字典,所以我们能像使用字典一样使用session

 执行完ctx.push后接着要执行

这个方法其实会去执行我们的视图函数,然后返回

返回时执行了self.finalize_request

这个方法中又执行了self.process_response,在这个方法中又执行了一步save_session的操作

其实是在执行

而session_interface = SecureCookieSessionInterface(),所以我们又要找到SecureCookieSessionInterface中的save_session方法

它实际上就是将数据序列化后写入了cookie

所以session的整体流程就是先从cookie中读取,然后返回一个特殊的字典对象,我们可以修改,最后执行完视图函数后,我们又将修改后的session序列化,然后写入cookie

特殊的装饰器

 View Code

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from flask import Flask, Request, render_template

app = Flask(__name__, template_folder='templates')
app.debug = True


@app.before_first_request # 只有第一次请求来时执行,后面的都不执行
def before_first_request1():
print('before_first_request1')


@app.before_first_request
def before_first_request2():
print('before_first_request2')


@app.before_request # 类似与django中间件中的process_request
def before_request1():
Request.nnn = 123
print('before_request1')


@app.before_request
def before_request2():
print('before_request2')


@app.after_request
def after_request1(response):
print('before_request1', response)
return response


@app.after_request # 类似与django中间件中的process_response
def after_request2(response):
print('before_request2', response)
return response


@app.errorhandler(404) # 当报404错误时返回的内容
def page_not_found(error):
return 'This page does not exist', 404


@app.template_global() # 定义全局的函数,每个页面都能使用
def sb(a1, a2):
return a1 + a2


@app.template_filter() # 定义过滤函数
def db(a1, a2, a3):
return a1 + a2 + a3


@app.route('/')
def hello_world():
return render_template('hello.html')


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

before_request和after_request

before_request是请求在执行视图函数之前会执行的,after_request是请求执行完视图函数会执行的

before_request如果返回None则会继续向后执行,当有多个时会按顺序执行,如果有返回值,那么后面的将不会执行,视图函数也不会执行,而是会按倒序执行after_request(这里和django的中间件有些不同)

有多个before_request时会按顺序执行

有多个after_request时会按倒序执行

闪现

session存在在服务端的一个字典里面,session保存起来,取一次里面还是有的,直到你删除之后才没有了

1、本质:flash是基于session创建的,flash支持往里边放值,只要你取一下就没有了,相当于pop了一下。不仅把值取走,而且把session里的东西去掉

2、闪现有什么用?

 View Code

from flask import Flask,session,Session,flash,get_flashed_messages,redirect,render_template,request
app = Flask(__name__)
app.secret_key ='sdfsdfsdf'

@app.route('/users')
def users():
# 方式一
# msg = request.args.get('msg','')
# 方式二
# msg = session.get('msg')
# if msg:
# del session['msg']
# 方式三
v = get_flashed_messages()
print(v)
return render_template('users.html',msg=v)

@app.route('/useradd')
def user_add():
# 在数据库中添加一条数据
# 假设添加成功,在跳转到列表页面时,显示添加成功
# 方式一
# return redirect('/users?msg=添加成功')
# 方式二
# session['msg'] = '添加成功'
# 方式三
flash('添加成功')
return redirect('/users')


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

flash中的值被取一次就会删除,不会保留

flash还可以分类设置

 View Code

from flask import Flask, session, flash, get_flashed_messages

app = Flask(__name__)
app.secret_key = 'asdfasdfasdf'


@app.route('/x1', methods=['GET', 'POST'])
def login():
flash('我要上向龙1', category='x1')
flash('我要上向龙2', category='x2')
return "视图函数x1"


@app.route('/x2', methods=['GET', 'POST'])
def index():
data = get_flashed_messages(category_filter=['x1'])
print(data)
return "视图函数x2"


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

中间件

通过上面的分析我们知道当请求过来时会先执行app.run-->run.simple-->app()-->__call__-->app.wsgi_app

如果我们自己定义了wsgi_app方法,那么就不会执行原来的,而会执行我们自己定义的了,利用这一点我们可以自己定义一个,让请求来了在执行app.wsgi_app之前和之后能执行一些我们自己的逻辑

 View Code

from flask import Flask
app = Flask(__name__)
app.secret_key = 'asdfasdfasdf'

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


class Middleware(object):
def __init__(self,old_wsgi_app):
"""
服务端启动时,自动执行
:param old_wsgi_app:
"""
self.old_wsgi_app =old_wsgi_app

def __call__(self, environ, start_response):
"""
每次有用户请求道来时
:param args:
:param kwargs:
:return:
"""
print('before')
obj = self.old_wsgi_app(environ, start_response)
print('after')
return obj

if __name__ == '__main__':
app.wsgi_app = Middleware(app.wsgi_app)
app.run()
"""
1.执行app.__call__
2.在调用app.wsgi_app方法
"""

这里要注意在执行app.wsgi_app之前我们无法使用request和session,只能使用最原始的数据

蓝图

在之前我们使用flask时所有的内容都是写在一个python文件中的,如果项目规模大了的话,这样做显然是不行的,所以我们需要创建一些项目的目录

目录结构类似django,manage.py是启动文件,内容如下

from s8pro import app

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

在导入s8pro时会执行该目录下的__init__文件,这个文件的内容

复制代码
from flask import Flask
from .views import account
from .views import admin
from .views import user


app = Flask(__name__)


app.register_blueprint(account.ac)
app.register_blueprint(admin.ad)
app.register_blueprint(user.us)
复制代码

这里我们实例化了一个app对象,然后将它和其它的蓝图关联

accout.py

复制代码
from flask import Blueprint,render_template
import redis

ac = Blueprint('ac',__name__)

@ac.route('/login')
def login():
    conn = redis.Redis()
    return render_template('login.html')


@ac.route('/logout')
def logout():
    return '123'
复制代码

admin.py

复制代码
from flask import Blueprint

ad = Blueprint('ad',__name__,url_prefix='/admin')

@ad.before_request
def bf():
    print('before_request')


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

@ad.route('/xxxx')
def xxxx():
    return 'xxxx'
复制代码

user.py

复制代码
from flask import Blueprint


us = Blueprint('us',__name__)

@us.route('/info')
def info():
    return 'info'
复制代码

在每个视图文件中我们都可以示例化一个蓝图对象,它的使用和app一样,最后只要把app和蓝图对象关联就可以访问到了

蓝图还可以定义访问url的前缀,类似于django中的include

ad = Blueprint('ad',__name__,url_prefix='/admin')

这样访问时url必须是/admin/***

蓝图中还可以定义before_request等方法,访问时只有访问到该蓝图中的内容时才会执行该方法,不是全局的

蓝图用于为应用提供目录划分:

小型应用程序:示例

大型应用程序:示例

其他:

  • 蓝图URL前缀:xxx = Blueprint('account', __name__,url_prefix='/xxx')
  • 蓝图子域名:xxx = Blueprint('account', __name__,subdomain='admin')
    # 前提需要给配置SERVER_NAME: app.config['SERVER_NAME'] = 'xxx.com:5000'
    # 访问时:admin.xxx.com:5000/login.html
原文地址:https://www.cnblogs.com/xyhh/p/10860389.html