flask web中app.config.from_data方法原理介绍

一:问题的引出

最近正在读flask web开发这本书,读到第七章, 因为在单一脚本中编写小型web程序很方便, 但是程序变复杂后, 使用单个大型源码文件会很不方便, 于是我们使用包和模块来组织大型程序。

我们之前的hello.py如下图所示:

不难看出程序实例app是先配置config变量,然后再用其初始化Manager, Bootstrap等拓展。

但是当我们改用包和模块来组织大型程序后,用python manage.py runserver 代替了原来的 python hello.py runserver 运行服务器,我们来看一下manage.py的内容:

发现其用了app/__inti__.py里面的create_app来创建程序实例,然后就直接初始化剩余的两个拓展了, 所以我们猜测create_app完成了config变量的配置, 和大部分拓展的初始化,我们来查看一下create_app这个函数:

我们发现 create_app先创建了app这个实例,然后调用代码,app.config.from_object(config[config_name]),然后对拓展进行初始化,我们猜测 ,这行代码的作用应该就是配置config变量,但是它是如何实现的呢?  下面我们来讨论这个问题:

一.我们首先从程序实例的创建开始谈起: app = Flask(__name__)

1.     Flask的构造函数里面调用了其基类_PackageBoundObject的构造函数




2.查看基类构造函数


(1)Import_name就是Flask(__name__)中的__name__参数,也就是模块的名字

(2)template_folder也就是静态文件static

(3)下面来看root_path= get_root_path(self.import_name)

3.找get_root_path                 


发现这个函数是返回模块所在包的路径。从前面可知,import_name的值就是Flask(__name__)中的__name__参数,__name__参数代表app包中的__init__.py模块,所以这个函数返回的也就是app包的路径。即root_path就是app包的路径。(注意,此处的app不是程序实例,是包名)

二.Falsk构造函数往下面看, 发现实例属性config:


1.找instance_relative_config


发现instance_relative_config是构造实例时传入的关键字参数,默认为Flase

 

2.在flask类里找到self.make_config


(1)self.root_path.

  前面我们知道root_path存的是模块所在包app的路径。­­­­

­­­­

(2)先找self.default_config


发现default_config是flask类的一个属性,ImmutableDict:不可变字典(?)

(3).找config_class


发现config_class是flask类的一个属性,其值Config是从config.py中导入的一个类

所以make_config函数里面的最后一句return self.config_class(root_path, self.default_config)就等价于:

return Config(root_path, self.default_config);

不难看出,self.config就是Config类的一个实例。

(4).Config类的构造函数


.                 

调用了dict的构造方法__init__,所以实例本身就是由defaults参数,也就是default_config构造的一个字典,而且实例有一个属性root_path,前面有介绍root_path就是模块所在包的路径。



经过以上分析我们可以知道,当我们调用app = Flask(__name__)时, 创建了Flask类的实例app, 并为其指定了一系列的属性, 其中的config属性是Config类的一个实例, 其本身是由实例的另一个属性self.default_config(上文可见)作为参数构造的一个字典。

三. 还记得我们在app/__init__.py里面的调用app.config.from_object(config[config_name])吗?

(1)config[config_name]

config是config.py里面的字典:


config_name是’default’

所以app.config.from_object(config[config_name])就等价于app.config.from_object(DevelopmentConfig)


    (1) DevelopmentConfig就是Config类的继承类,下面我们贴出config.py的代码:

        import os

        basedir = os.path.abspath(os.path.dirname(__file__))


        class Config:

            SECRET_KEY =os.environ.get('SECRET_KEY') or 'hard to guess string'

            SQLALCHEMY_COMMIT_ON_TEARDOWN = True

            SQLALCHEMY_TRACK_MODIFICATIONS= False

            MAIL_SERVER ='smtp.googlemail.com'

            MAIL_PORT = 587

            MAIL_USE_TLS = True

            MAIL_USERNAME =os.environ.get('MAIL_USERNAME')

            MAIL_PASSWORD =os.environ.get('MAIL_PASSWORD')

            FLASKY_MAIL_SUBJECT_PREFIX= '[Flasky]'

            FLASKY_MAIL_SENDER ='Flasky Admin <flasky@example.com>'

            FLASKY_ADMIN =os.environ.get('FLASKY_ADMIN')

 

            @staticmethod

            def init_app(app):

                pass

 

           class DevelopmentConfig(Config):

                DEBUG = True

                SQLALCHEMY_DATABASE_URI =os.environ.get('DEV_DATABASE_URL') or \

                   'sqlite:///' +os.path.join(basedir, 'data-dev.sqlite')

 

          class TestingConfig(Config):

               TESTING = True

               SQLALCHEMY_DATABASE_URI =os.environ.get('TEST_DATABASE_URL') or \

                  'sqlite:///' + os.path.join(basedir,'data-test.sqlite')

 

         class ProductionConfig(Config):

                 SQLALCHEMY_DATABASE_URI =os.environ.get('DATABASE_URL') or \

                    'sqlite:///' +os.path.join(basedir, 'data.sqlite')

 

         config = {

                'development': DevelopmentConfig,

                'testing': TestingConfig,

                'production':ProductionConfig,

 

               'default':DevelopmentConfig

        }

DevelopmentConfig有两个类属性,并且继承了其基类的属性和方法

(2)from_data

不难看出Config实例app.config的方法from_object肯定是在Config类里面:

app.config.from_object(DevelopmentConfig),obj参数就是DevelopmentConfig

所以for key in dir(obj):遍历到的就是Development里所有的属性和其继承到的属性:

然后if判断只要key是大写的就把key作为键,把key对应的值作为值,添加导self这个字典中,还记得self是什么的,没错就是app.config!


由此,我们可以的出结论:

    app.config.from_object(config[config_name])的作用就是配置所有的config变量。





已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页