Flask Source Code Reading Notes, flask source code reading

Source: Internet
Author: User

Flask Source Code Reading Notes, flask source code reading

I think I have developed a bad habit. I am very interested in its internal principles when using a framework. Sometimes it takes a lot of effort

Understanding, this also leads to slow learning, but in exchange for familiarity with the internal mechanism of the framework, as Hou Jie said, there is no secret in front of the source code. This is also

The direct cause of this article.

I. flask session principle flask sessions are implemented through client cookies. Unlike diango's server implementation, flask serializes session content to browser cookies through itsdangerous, when the browser requests the cookie content again, it will get the session content. For example, session ['name'] = 'kehan'. The client session is as follows,


We will decrypt the value stored in this cookie. This cookie is divided into three parts: Content serialization + time + tamper-proofing value.


Through the first part, we get the value of session ['name']. Let's take a look at the second part.


The second part stores the time. In order to reduce the timestamp value, the itsdangerous library has previously reduced the value by 118897263, so we need to add it. This time flask is used to determine whether the session has expired. The third part is the session value, timestamp, And the tamper-proofing value of our SECRET_KEY, which is signed by the HMAC algorithm. That is to say, even if you modify the previous value, because the signature value is incorrect, flask will not use this session. Therefore, you must save the SECRET_KEY and ensure its review degree. Otherwise, once you let others know the SECRET_KEY, You can construct a cookie to forge the session value. This is a terrible thing.
We know that generally to protect the session, the session generation will also contain the user_agent and remete_addr clients. If you feel that the protection provided by flask is insufficient, you can use the flask_login extension, one group uses this extension when using authentication in flask, which is easy to use and provides more intensive session protection.
2. One reason I like flask for the flask extension import principle is that the import is simple. Non-extended data can be imported through from flask, and all extensions are imported through from flask. ext. Which is very simple. When using django, you often don't remember where to import data. In the flask world, you don't have to worry about it. So what is the extended import principle of flask? Mainly implemented through sys. meta_path
When importing from falsk. ext. example import E, flask/ext/_ init _. py will be executed.
def setup():    from ..exthook import ExtensionImporter    importer = ExtensionImporter(['flask_%s', 'flaskext.%s'], __name__)    importer.install()
Install will add a module loading class to sys. meta_path. When the import operation is performed, it will call its find_module. If the returned result is not None, it will call load_module to load
For example, when we import Manager from flask. ext. script
Will call find_module ('flask. ext. script'), prefinx is flask. ext, so it will call load_module ()
In this case, you will try to import the flask_script module or flaskext. script
   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)

Iii. Principles of flask sqlalchemy
Sqlalchemy is the most powerful orm framework in python. It is undoubtedly more complicated to use sqlalchemy than the built-in orm of django. Using the flask sqlalchemy extension will bring you closer to django's ease of use. First, let's talk about two important configurations.
App. config ['sqlalchemy _ ECHO '] = True = "configure the output SQL statement
App. config ['sqlalchemy _ commit_on_tearlow'] = True = "automatically submit db. session. commit () each request (),
If one day you find db. session. add in other written views, but there is no db. session. commit, you must have configured the above options. This is achieved through app. teardown_appcontext Registration
        @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_exc
Response_or_exc is an abnormal value. The default value is sys. exc_info () [1].
Self. session. remove () indicates that the self. session will be destroyed after each request. Why?
This is the session object of sqlalchemy.
From sqlalchemy. orm import sessionmaker
Session = sessionmaker ()
For example, we will use the sessionmaker () factory function to create a session, but this session cannot be used in multiple threads. To support multi-threaded operations, sqlalchemy provides scoped_session, the scoped_session is implemented through a certain scope.
Therefore, the following session is used in multiple threads:
From sqlalchemy. orm import scoped_session, sessionmaker
Session = scoped_session (sessionmaker ())

Let's take a look at how scoped_session provides multi-threaded environment support.
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)
In _ init _, session_factory is the factory function used to create the session, while sessionmaker is a factory function (which actually defines the _ call _ function) scopefunc is a function that can generate a specific scope. If it is not provided, ThreadLocalRegistry will be used.
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
From the above _ call _, we can see that a new session will be created every time and the session will be concurrently stored in the local variable of the thread. You may wonder where _ call _ is called?
def instrument(name):    def do(self, *args, **kwargs):        return getattr(self.registry(), name)(*args, **kwargs)    return dofor meth in Session.public_methods:    setattr(scoped_session, meth, instrument(meth))
As we can see, when we call session. query will call getattr (self. registry (), 'query'), self. registry () is the time to call _, but ThreadLocalRegistry is not used in flask_sqlalchemy. The process for creating scoped_session is as follows:

# Which stack should we use?  _app_ctx_stack is new in 0.9connection_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        )
We can see that scopefunc is set to connection_stack. _ ident_func __, and connection_stack is the app context in flask,
If you have read the previous article, you will know that _ ident_func _ is actually thrading. get_ident in multithreading, that is, thread id.
Let's see how ScopedRegistry operates through _
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())
The Code is also very simple. In fact, it is to create the corresponding session object based on the thread id. Here we have basically learned the magic of flask_sqlalchemy, which is similar to the flask cookie and g, are there two small issues?
1. Can I use ThreadLocalRegistry for flask_sqlalchemy?
In most cases, this is acceptable, but it is not applicable if wsgi uses the greenlet mode for multi-concurrency.
2. What is partial in create_scoped_session above?
As we mentioned earlier, the session_factory of scoped_session is a callable object, but the _ SignallingSession class does not define _ call __. Therefore, It is supported through partial.

At this point, you will know why self. session. remove () is required at the end of each request. Otherwise, the field storing the session will be too large.

The following code describes how to understand db. relationship lazy:
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'))
Assume that the role is an instance of the obtained Role.
Lazy: dynamic => role. users does not return the User list, And sqlalchemy. orm. dynamic. AppenderBaseQuery object is returned.
When you execute role. users. all (), the SQL statement is executed. The advantage is that you can continue filtering.

Lazy: select => role. users directly returns the list of User instances, that is, directly execute SQL

Note: db. session. commit only performs update when the object changes.

Iv. flask moment principle flask moment is a simple encapsulation of moment. js. moment. js provides time support through js. If you are interested, you can pay attention to it and enjoy powerful functions. The flask moment principle is very simple. After loading the dom with a time format string, use moment. js to process it,
In this step, moment. include_moment () is completed. If you use other languages, such as Chinese, call moment. lang ('zh-cn ')
If flask bootstrap is used, you only need to add the following code at the end (jquery is required)
{% block scripts %}{{ super() }}{{ moment.include_moment() }}{{ moment.lang('zh-cn') }}{% endblock %}
Flask moment also provides statistics on the time elapsed. If refresh is set to True, the refresh is refreshed once every minute. refresh can also be used to refresh the time, in minutes.
{Moment (current_time). fromNow (refresh = True )}}

As shown above, we know that flask moment has imported the moment object in the template. How is this implemented?
    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 is used to add an attribute to the template context.
Def render_template (template_name_or_list, ** context ):
Ctx. app. update_template_context (context)

In render_template, the previously registered variables are added to context, so you can use moment in the template,
Flask bootstrap is implemented through app. jinja_env.globals ['bootstrap _ find_resource '] = bootstrap_find_resource.

We know that flask injects request, g, session, and so on into the global environment when initializing the jinja environment.
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        )
However, when I read the source code, I found that _ default_template_ctx_processor will also inject g, request, as shown below:
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
This is not a repetition. What is necessary?
Haha. Take the comments of rv. globals. update above for details.
The flask template can use macros and must be imported using import. In this case, the imported template cannot access the local variables of the current template, but only global variables can be used.
This is why g, request, and session exist in global, that is, to support the use of g objects in macros and the import of local variables to g is for efficiency, for more information, see jinja2.







Kneeling: Reading Notes or annotations of H264 standard T264 source code

Zhidao.baidu.com/..?c2=eb
 
How to read open source code

By reading open source code, you can learn the frameworks and patterns, code skills, algorithms, and so on. However, some people often do not know how to start after getting the open source code. Here are some of my experiences.
1. Compile and run the code, understand what it does, and implement the function.
2. Read from the entry point and follow the process to learn how the software runs.
3. Observe the components of the software as a whole. It is best to draw a picture.
4. modify the software function and debug it. You cannot just read the code, but you must modify the code to increase understanding of the open source code.
5. Take notes and record the functions, implementation methods, design frameworks, module organization, and code skills of the open-source code implementation.

The above is just my personal experience and I hope to help you.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.