博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
flask web中app.config.from_data方法原理介绍
阅读量:4095 次
发布时间:2019-05-25

本文共 3580 字,大约阅读时间需要 11 分钟。

一:问题的引出

最近正在读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变量。

你可能感兴趣的文章
ACfly也是基于FreeRTOS的
查看>>
carzepony也在想往FreeRTOS上迁移
查看>>
我发觉,不管是弄ROS OPENCV T265二次开发 SDK开发 caffe PX4 都是用的C++
查看>>
ROS的安装(包含文字和视频教程,我的ROS安装教程以这篇为准)
查看>>
原来我之前一直用的APM固件....现在很多东西明白了。
查看>>
realsense-ros里里程计相关代码
查看>>
似乎写个ROS功能包并不难,你会订阅话题发布话题,加点逻辑处理,就可以写一些基础的ROS功能包了。
查看>>
我觉得在室内弄无人机开发装个防撞机架还是很有必要的,TBUS就做得很好。
查看>>
serial也是见到很多次了,似乎它就是一种串行通信协议
查看>>
TBUS的一些信息
查看>>
专业和业余的区别就在于你在基础在基本功打磨练习花的时间
查看>>
通过mavlink实现自主航线的过程笔记
查看>>
Ardupilot飞控Mavlink代码学习
查看>>
这些网站有一些嵌入式面试题合集
查看>>
我觉得刷题是有必要的,不然小心实际被问的时候懵逼,我觉得你需要刷个50份面试题。跟考研数学疯狂刷卷子一样!
查看>>
我觉得嵌入式面试三要素:基础吃透+项目+大量刷题,缺一不可。不刷题是不行的。而且得是大量刷,刷出感觉套路,别人做题都做得是固定题型套路条件反射了,你还在那慢慢理解慢慢推是不行的,也是考研的教训。
查看>>
React Native之原理浅析
查看>>
Git操作清单
查看>>
基础算法
查看>>
前端面试
查看>>