关键代码展示
def __init__(
self,
import_name,
static_url_path=None,
static_folder="static",
static_host=None,
host_matching=False,
subdomain_matching=False,
template_folder="templates",
instance_path=None,
instance_relative_config=False,
root_path=None,
):
_PackageBoundObject.__init__(
self, import_name, template_folder=template_folder, root_path=root_path
)
self.static_url_path = static_url_path
self.static_folder = static_folder
if instance_path is None:
instance_path = self.auto_find_instance_path()
elif not os.path.isabs(instance_path):
raise ValueError(
"If an instance path is provided it must be absolute."
" A relative path was given instead."
)
可以看到flask框架在初始化的过程中可以传入10个参数,除了第一个参数必填以外其他的都是有默认参数的非必填选项。下面我将按照顺序对这10个参数做介绍:
- import_name
从flask的源代码中可以看出,import_name主要是传递给了_PackageBoundObject的init方法,我们来看看这个方法
def __init__(self, import_name, template_folder=None, root_path=None):
self.import_name = import_name
self.template_folder = template_folder
if root_path is None:
root_path = get_root_path(self.import_name)
self.root_path = root_path
self._static_folder = None
self._static_url_path = None
# circular import
from .cli import AppGroup
可以看到,最终是将import_name通过get_root_path方法转化为root_path属性存储起来。我们来看一下转换过程
def get_root_path(import_name):
"""Returns the path to a package or cwd if that cannot be found. This
returns the path of a package or the folder that contains a module.
Not to be confused with the package path returned by :func:`find_package`.
"""
# Module already imported and has a file attribute. Use that first.
mod = sys.modules.get(import_name)
if mod is not None and hasattr(mod, "__file__"):
return os.path.dirname(os.path.abspath(mod.__file__))
# Next attempt: check the loader.
loader = pkgutil.get_loader(import_name)
# Loader does not exist or we're referring to an unloaded main module
# or a main module without path (interactive sessions), go with the
# current working directory.
if loader is None or import_name == "__main__":
return os.getcwd()
# For .egg, zipimporter does not have get_filename until Python 2.7.
# Some other loaders might exhibit the same behavior.
if hasattr(loader, "get_filename"):
filepath = loader.get_filename(import_name)
else:
# Fall back to imports.
__import__(import_name)
mod = sys.modules[import_name]
filepath = getattr(mod, "__file__", None)
# If we don't have a filepath it might be because we are a
# namespace package. In this case we pick the root path from the
# first module that is contained in our package.
if filepath is None:
raise RuntimeError(
"No root path can be found for the provided "
'module "%s". This can happen because the '
"module came from an import hook that does "
"not provide file name information or because "
"it's a namespace package. In this case "
"the root path needs to be explicitly "
"provided." % import_name
)
# filepath is import_name.py for a module, or __init__.py for a package.
return os.path.dirname(os.path.abspath(filepath))
从这个脚本可以看出,最终通过这个import参数来获得web服务器的根路径。
- static_url_path
可以通过参数注解来大概了解一下他的作用
:param static_url_path: can be used to specify a different path for the
static files on the web. Defaults to the name
of the `static_folder` folder.
也就是说通过这个参数,我们可以指定静态资源的路径,这个路径最终指向了static_folder设置的文件夹位置
- static_folder
可以通过参数注解来大概了解一下他的作用
:param static_folder: The folder with static files that is served at
``static_url_path``. Relative to the application ``root_path``
or an absolute path. Defaults to ``'static'``.
也就是说通过这个参数,我们可以指定静态资源的的文件名,默认情况下叫static
- static_host
可以通过参数注解来大概了解一下他的作用
:param static_host: the host to use when adding the static route.
Defaults to None. Required when using ``host_matching=True``
with a ``static_folder`` configured.
也就是说,当我们的静态资源文件和服务端脚本不在一块时,我们可以通过配置这个参数来实现远程资源的加载。前提是我们配置host_matching=True
- host_matching
作用参照上面
- subdomain_matching
可以通过参数注解大概了解一下他的作用
:param subdomain_matching: consider the subdomain relative to
:data:`SERVER_NAME` when matching routes. Defaults to False.
遵循子域名的匹配,默认为false,在源码中可以看到,subdomain_matching主要是用于bind_to_environ方法中
if request is not None:
# If subdomain matching is disabled (the default), use the
# default subdomain in all cases. This should be the default
# in Werkzeug but it currently does not have that feature.
subdomain = (
(self.url_map.default_subdomain or None)
if not self.subdomain_matching
else None
)
return self.url_map.bind_to_environ(
request.environ,
server_name=self.config["SERVER_NAME"],
subdomain=subdomain,
)
进入bind_to_environ方法中,可以看到subdomain主要是为了配合uwsgi时拼接子域名
def bind_to_environ(self, environ, server_name=None, subdomain=None):
environ = _get_environ(environ)
wsgi_server_name = get_host(environ).lower()
if server_name is None:
server_name = wsgi_server_name
else:
server_name = server_name.lower()
if subdomain is None and not self.host_matching:
cur_server_name = wsgi_server_name.split(".")
real_server_name = server_name.split(".")
offset = -len(real_server_name)
if cur_server_name[offset:] != real_server_name:
# This can happen even with valid configs if the server was
# accesssed directly by IP address under some situations.
# Instead of raising an exception like in Werkzeug 0.7 or
# earlier we go by an invalid subdomain which will result
# in a 404 error on matching.
subdomain = "<invalid>"
else:
subdomain = ".".join(filter(None, cur_server_name[:offset]))
- template_folder
可以通过参数注解来大概了解下他的作用
:param template_folder: the folder that contains the templates that should
be used by the application. Defaults to
``'templates'`` folder in the root path of the
application.
通过注解可以看出,template_folder的主要作用是放静态模板页面的地方,默认放在templates文件夹下,但可以通过修改这个变量来修改静态模板的存放位置
- instance_path
可以通过参数注解来大概了解一下他的作用
:param instance_path: An alternative instance path for the application.
By default the folder ``'instance'`` next to the
package or module is assumed to be the instance
path.
可以看出,我们可以通过instance_path来设置导入包的路径,这样可以隐藏比较敏感的配置
- instance_relative_config
可以通过参数注解来大概了解一下他的作用
:param instance_relative_config: if set to ``True`` relative filenames
for loading the config are assumed to
be relative to the instance path instead
of the application root.
主要是和instan_path来实现导入包路径的替换,相当于一个开关
- root_path
可以通过参数注解来了解一下他的大概作用
:param root_path: Flask by default will automatically calculate the path
to the root of the application. In certain situations
this cannot be achieved (for instance if the package
is a Python 3 namespace package) and needs to be
manually defined.
可以看出,通过修改这个root_path来修改服务端脚本的根路径。这个在import包的时候很重要。import包的时候flask会在前面拼接root_path来找到这个包