标签:python flask 源码
我觉得我已经养成了一个坏习惯,在使用一个框架过程中对它的内部原理非常感兴趣,有时候需要花不少精力才
明白,这也导致了学习的缓慢,但换来的是对框架的内部机理的熟悉,正如侯捷所说,源码面前,了无秘密。这也是
本文产生的直接原因。
def setup(): from ..exthook import ExtensionImporter importer = ExtensionImporter([‘flask_%s‘, ‘flaskext.%s‘], __name__) importer.install()install将会向sys.meta_path添加模块装载类,当import时会调用其find_module,如果返回非None,会调用load_module加载
def install(self): sys.meta_path[:] = [x for x in sys.meta_path if self != x] + [self] def find_module(self, fullname, path=None): if fullname.startswith(self.prefix): return self def load_module(self, fullname): modname = fullname.split(‘.‘, self.prefix_cutoff)[self.prefix_cutoff] for path in self.module_choices: realname = path % modname __import__(realname)
@teardown def shutdown_session(response_or_exc): if app.config[‘SQLALCHEMY_COMMIT_ON_TEARDOWN‘]: if response_or_exc is None: self.session.commit() self.session.remove() return response_or_excresponse_or_exc为异常值,默认为sys.exc_info()[1]
class scoped_session(object): def __init__(self, session_factory, scopefunc=None): self.session_factory = session_factory if scopefunc: self.registry = ScopedRegistry(session_factory, scopefunc) else: self.registry = ThreadLocalRegistry(session_factory)__init__中,session_factory是创建session的工厂函数,而sessionmaker就是一工厂函数(其实是定义了__call__的
class ThreadLocalRegistry(ScopedRegistry): def __init__(self, createfunc): self.createfunc = createfunc self.registry = threading.local() def __call__(self): try: return self.registry.value except AttributeError: val = self.registry.v从上面__call__可以看出,每次都会创建新的session,并发在线程本地变量中,你可能会好奇__call__是在哪里调用的?
def instrument(name): def do(self, *args, **kwargs): return getattr(self.registry(), name)(*args, **kwargs) return do for meth in Session.public_methods: setattr(scoped_session, meth, instrument(meth))正如我们所看到的,当我们调用session.query将会调用 getattr(self.registry(), ‘query‘),self.registry()就是
# Which stack should we use? _app_ctx_stack is new in 0.9 connection_stack = _app_ctx_stack or _request_ctx_stack def __init__(self, app=None, use_native_unicode=True, session_options=None): session_options.setdefault( ‘scopefunc‘, connection_stack.__ident_func__ ) self.session = self.create_scoped_session(session_options) def create_scoped_session(self, options=None): """Helper factory method that creates a scoped session.""" if options is None: options = {} scopefunc=options.pop(‘scopefunc‘, None) return orm.scoped_session( partial(_SignallingSession, self, **options), scopefunc=scopefunc )我们看到scopefunc被设置为connection_stack.__ident_func__,而connection_stack就是flask中app上下文,
class ScopedRegistry(object): def __init__(self, createfunc, scopefunc): self.createfunc = createfunc self.scopefunc = scopefunc self.registry = {} def __call__(self): key = self.scopefunc() try: return self.registry[key] except KeyError: return self.registry.setdefault(key, self.createfunc())代码也很简单,其实也就是根据线程id创建对应的session对象,到这里我们基本已经了解了flask_sqlalchemy的
class Role(db.Model): __tablename__ = ‘roles‘ id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(64), unique=True) users = db.relationship(‘User‘, backref=‘role‘, lazy=‘dynamic‘) class User(db.Model): __tablename__ = ‘users‘ id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(64), unique=True, index=True) role_id = db.Column(db.Integer, db.ForeignKey(‘roles.id‘))假设role是已经获取的一个Role的实例
{% block scripts %} {{ super() }} {{ moment.include_moment() }} {{ moment.lang(‘zh-cn‘) }} {% endblock %}flask moment还提供了过了多长时间统计,refresh为True时,每分钟刷新一次,refresh也可为具体的刷新时间,
def init_app(self, app): if not hasattr(app, ‘extensions‘): app.extensions = {} app.extensions[‘moment‘] = _moment app.context_processor(self.context_processor) @staticmethod def context_processor(): return { ‘moment‘: current_app.extensions[‘moment‘] }通过app.context_processor给模板上下文添加了额为属性
rv.globals.update( url_for=url_for, get_flashed_messages=get_flashed_messages, config=self.config, # request, session and g are normally added with the # context processor for efficiency reasons but for imported # templates we also want the proxies in there. request=request, session=session, g=g )但我在看源码时发现_default_template_ctx_processor也会注入g,request,如下
def _default_template_ctx_processor(): """Default template context processor. Injects `request`, `session` and `g`. """ reqctx = _request_ctx_stack.top appctx = _app_ctx_stack.top rv = {} if appctx is not None: rv[‘g‘] = appctx.g if reqctx is not None: rv[‘request‘] = reqctx.request rv[‘session‘] = reqctx.session return rv这不是重复嘛,有啥必要呢?
标签:python flask 源码
原文地址:http://blog.csdn.net/yueguanghaidao/article/details/40016235