一:安装flask
workon flask_project 进入虚拟后安装flask
pip install flask==0.10.1 安装指定的版本
进入虚拟环境的目录,查看创建的所有的虚拟环境,创建的虚拟环境中有指定的python解释器
进入虚拟环境,查看包的管理
总结:虚拟环境与真实环境怎么进行隔离:1.python解释器的隔离 2.包管理的隔离
二:项目迁移
加入项目迁移到别的机器上,那么项目运行所依赖的包,就要到新机器上重亲一个一个重新安装,比较麻烦,经pip的包名生成文件,方便迁移
pip freeze > requirements.txt
三:pycharm创建创建一个桌面目录,项目解释器选择flask_project虚拟环境里面的python3。
1.工程文件下,创建一个hello.py文件
hello.py
from flask import Flask # 创建flask的应用对象 app = Flask(__name__) # 这样设定,就是可以让这个包被别人导入后,__name__== hello.py,判断条件下不满足,因此一般作为程序的入口。 if __name__ == "__main__": pass
2.创建静态文件和模板文件夹:
静态文件夹:static
模板文件夹:templates
3.定义视图函数
hello.py
from flask import Flask # 从flask包中导入一个Flaks类 app = Flask(__name__) # 创建一个实例对象 __name__是必传的参数 @app.route("/") def index(): """ 定义视图函数 :return: """ return "hello flask" if __name__ == "__main__": app.run()
运行这个hello.py,控制台显示
点击或者浏览器输入网址得到:
四:总结程序运行的基本思路
点击app.route进入看源码:route函数
def route(self, rule, **options): """A decorator that is used to register a view function for a # 用于注册视图函数的装饰器,参数为给定的rule规则。 given URL rule. This does the same thing as :meth:`add_url_rule` but is intended for decorator usage:: @app.route('/') def index(): return 'Hello World' For more information refer to :ref:`url-route-registrations`. :param rule: the URL rule as string # url规则的字符串 :param endpoint: the endpoint for the registered URL rule. Flask itself assumes the name of the view function as endpoint # 注册视图规则的端点,flask中假设视图函数的名字为endpoint :param options: the options to be forwarded to the underlying # 请求方式,get,post,默认是get请求方式 :class:`~werkzeug.routing.Rule` object. A change to Werkzeug is handling of method options. methods is a list of methods this rule should be limited to (`GET`, `POST` etc.). By default a rule just listens for `GET` (and implicitly `HEAD`). Starting with Flask 0.6, `OPTIONS` is implicitly added and handled by the standard request handling. """ def decorator(f): endpoint = options.pop('endpoint', None) self.add_url_rule(rule, endpoint, f, **options) return f return decorator # 返回一个decorate函数的引用
装饰器:用route函数,装饰index函数
def route(self,route,**options): def decorate(f): endpoint = options.pop("endpoint",None) self.add_url_rule(rule, endpoint,f,**options) return f return decorator @route("/") def index(): pass
# 相当于
route = route("/")
route(index)
f是什么东西呢?add_url_rule是什么东西呢?点击进如add_url_rule函数: 解释:f 就是视图函数的引用 route就是:"/"
@setupmethod def add_url_rule(self, rule, endpoint=None, view_func=None, **options): """Connects a URL rule. Works exactly like the :meth:`route` decorator. If a view_func is provided it will be registered with the endpoint. Basically this example:: @app.route('/') def index(): pass Is equivalent to the following:: def index(): pass app.add_url_rule('/', 'index', index) If the view_func is not provided you will need to connect the endpoint to a view function like so:: app.view_functions['index'] = index Internally :meth:`route` invokes :meth:`add_url_rule` so if you want to customize the behavior via subclassing you only need to change this method. For more information refer to :ref:`url-route-registrations`. .. versionchanged:: 0.2 `view_func` parameter added. .. versionchanged:: 0.6 `OPTIONS` is added automatically as method. :param rule: the URL rule as string :param endpoint: the endpoint for the registered URL rule. Flask itself assumes the name of the view function as endpoint :param view_func: the function to call when serving a request to the # 视图函数的引用 provided endpoint :param options: the options to be forwarded to the underlying :class:`~werkzeug.routing.Rule` object. A change to Werkzeug is handling of method options. methods is a list of methods this rule should be limited to (`GET`, `POST` etc.). By default a rule just listens for `GET` (and implicitly `HEAD`). Starting with Flask 0.6, `OPTIONS` is implicitly added and handled by the standard request handling. """ if endpoint is None: # 没有指明endpoint,默认的用的是视图函数的名字,怎么实现的呢? endpoint = _endpoint_from_view_func(view_func) # options['endpoint'] = endpoint methods = options.pop('methods', None) # if the methods are not given and the view_func object knows its # methods we can use that instead. If neither exists, we go with # a tuple of only `GET` as default. if methods is None: methods = getattr(view_func, 'methods', None) or ('GET',) methods = set(methods) # Methods that should always be added required_methods = set(getattr(view_func, 'required_methods', ())) # starting with Flask 0.8 the view_func object can disable and # force-enable the automatic options handling. provide_automatic_options = getattr(view_func, 'provide_automatic_options', None) if provide_automatic_options is None: if 'OPTIONS' not in methods: provide_automatic_options = True required_methods.add('OPTIONS') else: provide_automatic_options = False # Add the required methods now. methods |= required_methods # due to a werkzeug bug we need to make sure that the defaults are # None if they are an empty dictionary. This should not be necessary # with Werkzeug 0.7 options['defaults'] = options.get('defaults') or None rule = self.url_rule_class(rule, methods=methods, **options) rule.provide_automatic_options = provide_automatic_options self.url_map.add(rule) if view_func is not None: old_func = self.view_functions.get(endpoint) if old_func is not None and old_func != view_func: raise AssertionError('View function mapping is overwriting an ' 'existing endpoint function: %s' % endpoint) self.view_functions[endpoint] = view_func
先看setupmethos这个函数,也是一个装饰器
def setupmethod(f): """Wraps a method so that it performs a check in debug mode if the first request was already handled. """ def wrapper_func(self, *args, **kwargs): if self.debug and self._got_first_request: raise AssertionError('A setup function was called after the ' 'first request was handled. This usually indicates a bug ' 'in the application where a module was not imported ' 'and decorators or other functionality was called too late. ' 'To fix this make sure to import all your view modules, ' 'database models and everything related at a central place ' 'before the application starts serving requests.') return f(self, *args, **kwargs) return update_wrapper(wrapper_func, f)
def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
if endpoint is None: # 没有指明endpoint,默认的用的是视图函数的名字,怎么实现的呢?
endpoint = _endpoint_from_view_func(view_func) #
options['endpoint'] = endpoint
methods = options.pop('methods', None)
provide_automatic_options = getattr(view_func,
'provide_automatic_options', None)
if provide_automatic_options is None:
if 'OPTIONS' not in methods:
provide_automatic_options = True
required_methods.add('OPTIONS')
else:
provide_automatic_options = False
options['defaults'] = options.get('defaults') or None
rule = self.url_rule_class(rule, methods=methods, **options)
rule.provide_automatic_options = provide_automatic_options
self.url_map.add(rule)
if view_func is not None:
old_func = self.view_functions.get(endpoint)
if old_func is not None and old_func != view_func:
raise AssertionError('View function mapping is overwriting an '
'existing endpoint function: %s' % endpoint)
self.view_functions[endpoint] = view_func
# 相当于
setmethod = setmethod(add_url_rule)
setmethod()
化简函数,分析setmethods怎么装饰函数add_url_rule
def setupmethod(f): # f函数其实就是add_url_role函数 def wrapper_func(self, *args, **kwargs): if self.debug and self._got_first_request: raise AssertionError('A setup function was called after the ' 'first request was handled. This usually indicates a bug ' 'in the application where a module was not imported ' 'and decorators or other functionality was called too late. ' 'To fix this make sure to import all your view modules, ' 'database models and everything related at a central place ' 'before the application starts serving requests.') return f(self, *args, **kwargs) return update_wrapper(wrapper_func, f) # 等价于 return wrapper
setupmethod = settupmethod(add_url_role)
setupmethod() # update_wrapper(wrapper_func,add_url_role)
来看看update_wrapper()函数:
WAPPER_ASSIGNMENTS = ("__module","__name__","__qualname__","__doc__","__annotation__") # 提前定义好的常量
WRAPPER_UPDATES = ("__dict__") # 提前定义好的常量
def update_wrapper(wrapper, wrapper == wrapper_func wrapped, wrapperd == add_url_role assigned = WRAPPER_ASSIGNMENTS, updated = WRAPPER_UPDATES): """Update a wrapper function to look like the wrapped function # wrapper is the function to be updated # 内层函数wrapper_func wrapped is the original function # 原始函数 add_url_role assigned is a tuple naming the attributes assigned directly from the wrapped function to the wrapper function (defaults to functools.WRAPPER_ASSIGNMENTS) updated is a tuple naming the attributes of the wrapper that are updated with the corresponding attribute from the wrapped function (defaults to functools.WRAPPER_UPDATES) """ for attr in assigned: try: value = getattr(wrapped, attr) except AttributeError: pass else: setattr(wrapper, attr, value) for attr in updated: getattr(wrapper, attr).update(getattr(wrapped, attr, {})) # Issue #17482: set __wrapped__ last so we don't inadvertently copy it # from the wrapped function when updating __dict__ wrapper.__wrapped__ = wrapped # Return the wrapper so this can be used as a decorator via partial() return wrapper # 返回值还是内函数的引用,为什么要这么麻烦,多写这么多的代码?
# getattr函数的作用?settattr函数的作用?
def a(): pass def b(): pass WAPPER_ASSIGNMENTS = ("__module","__name__","__qualname__","__doc__","__annotation__") for attr in WAPPER_ASSIGNMENTS: try: value = getattr(a,attr) print("a函数的{}属性值是{}".format(attr,value)) except AttributeError: pass else: setattr(b,attr,value) # 把b函数的__name__的值设置成a的__name__的值 print(b.__name__) # 打印的结果 a函数的__name__属性值是a a函数的__qualname__属性值是a a函数的__doc__属性值是None a
endpoint到底是个啥东西,怎么默认值为None,官方解释确实endpoint默认为视图函数的名字呢?点进_endpoint_from_view_func(view_func):
def _endpoint_from_view_func(view_func): """Internal helper that returns the default endpoint for a given function. This always is the function name. """ assert view_func is not None, 'expected view func if endpoint ' # view_func本来就是None,默认值为None 'is not provided.' return view_func.__name__ # 返回view_func.__name__名称