Flask入门

Web框架的本质是什么?

对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端。

参考:http://www.cnblogs.com/wupeiqi/articles/5237672.html

import socket

def handle_request(client):
    buf = client.recv(1024)
    header = "HTTP/1.1 200 OK\r\n\r\n"
    body = "Hello, Standby!"
    client.send((header+body).encode())

def main():
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind(('localhost', 9000))
    sock.listen(5)

    while True:
        connection, address = sock.accept()
        handle_request(connection)
        connection.close()

if __name__ == '__main__':
    main()

  

 

wsgi是什么?

Web Server Gateway Interface/web服务网关接口,是一套协议规范。

python标准库提供的独立WSGI服务器称为wsgiref(Django没有自己实现socket,而是采用的wsgiref模块)。

wsgiref 、werkzeug以及uwsgi都是实现了 wsgi协议(规范)的模块。

from wsgiref.simple_server import make_server

def RunServer(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return [bytes('<h1>Hello, web!</h1>', encoding='utf-8'), ]

if __name__ == '__main__':
    httpd = make_server('', 8080, RunServer)
    print("Serving HTTP on port 8080...")
    httpd.serve_forever()

 

 

Flask简介

参考:http://www.cnblogs.com/wupeiqi/articles/7552008.html

Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架。

 

 

Flask示例

Flask demo01  (有参装饰器方式,参考:http://www.cnblogs.com/standby/p/8271157.html

from flask import Flask

app = Flask(__name__)

@app.route('/index')
def index():
    return "Index"

if __name__ == '__main__':
    app.run()

Flask demo02  (类似Django的方式)

from flask import Flask

app = Flask(__name__)

def index():
    return "Index"

app.add_url_rule('/index','reverse_url_name',index)

if __name__ == '__main__':
    app.run()

 

 

Flask依赖实现了wsgi协议的模块:werkzeug

werkzeug不依赖Flask,自己单独可以运行。

from werkzeug.wrappers import Request, Response
from werkzeug.serving import run_simple

@Request.application
def hello(request):
    return Response('Hello World!')

if __name__ == '__main__':
    run_simple('localhost', 4000, hello)

  

werkzeug.serving.run_simple 这个方法前两个参数是ip和port,第三个参数是函数,那么当然也可以是对象喽。 
再结合上面的Flask Demo程序,

app.run()
run_simple(host, port, self, **options)
那么这个self就是 app 这个object,所以 app() 这样就调用了 app.__call__方法

def __call__(self, environ, start_response):
    """Shortcut for :attr:`wsgi_app`."""
    return self.wsgi_app(environ, start_response)

故:Flask应用的入口就是 wsgi_app(...) 这里。

__call__方法干了什么?
	- 一旦请求到达,执行app.__call__方法
	- __call__方法封装用户请求(封装成一个request对象)
	- 进行路由匹配

  

 

@app.route('/index')
def index():
    return "Index"

本质是什么?

是用一个带参数的装饰器装饰了 index函数

详见:

def route(self, rule, **options):
    """A decorator that is used to register a view function for a
    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
    :param endpoint: the endpoint for the registered URL rule.  Flask
                     itself assumes the name of the view function as
                     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.
    """
    def decorator(f):
        endpoint = options.pop('endpoint', None)
        self.add_url_rule(rule, endpoint, f, **options)
        return f
    return decorator

所以 @app.route('/index') 即 @decorator

@decorator
def index():
    return "Index"


def decorator(index):
	endpoint = options.pop('endpoint', None)
    self.add_url_rule(rule, endpoint, index, **options)
    return index

最后:

self.add_url_rule 里进一步调用:
    # 首先把路由关系封装到一个Rule对象里,类似于{'url':'/index', 'method':index}
    rule = self.url_rule_class(rule, methods=methods, **options)
    rule.provide_automatic_options = provide_automatic_options
    # 其次将路由关系添加到一个 Map对象里,类似于一个保存路由关系的列表。
    self.url_map.add(rule)

所以,最后所有的路由关系就保存在了app.url_map字段里了。

 

 

Django和Flask比较

Django
	- 无socket,用的第三方wsgi模块
	- 中间件
	- 路由系统
	- 视图(CBV 和 FBV)
	- 模板
	- ORM
	- cookie 
	- session
	- Admin
	- Form
	- 缓存
	- 信号
	- 序列化
	- ...

Flask  轻量级框架
	- 无socket,用的第三方wsgi模块
	- 中间件(功能比较弱,需要加上扩展)
	- 路由系统
	- 视图(CBV 和 FBV)
	- 无模板,用第三方Jinja2模板
	- 无ORM
	- cookie    
	- session(比较弱)

 

Flask简单登录示例

from flask import Flask
from flask import render_template
from flask import make_response
from flask import redirect
from flask import request
from flask import session


app = Flask(__name__)
app.secret_key = 'ahlaskdfhzxadqax'  # "加盐":用这个key把用户信息加密返回给客户端,当做cookie存储在客户端浏览器中,减少服务端压力。
# app = Flask(__name__,template_folder='my_templates',root_path='xxx',static_url_path='/static_file_prefix')
# print(app.root_path)
# @app.route('/login')  默认的method只有 GET
# @app.route('/login',endpoint='alias_name')  endpoint参数用于指定别名,从而可以反向生成url,使用url_for(alias_name)则可以拿到对应url

@app.route('/login',methods=['GET','POST'])
def login():
    if 'GET' == request.method:
        # print(request.query_string)
        return render_template('login.html')
    elif 'POST' == request.method:
        '''
        print(request)  # <Request 'http://127.0.0.1:5000/login?v=123' [POST]>
        print(request.values)  # CombinedMultiDict([ImmutableMultiDict([('v', '123')]), ImmutableMultiDict([('user', 'alex'), ('pwd', 'xxxooo')])])
        print(request.form)  # ImmutableMultiDict([('user', 'alex'), ('pwd', 'xxxooo')])
        print(request.data)  # b''
        print(request.query_string)  # b'v=123'
        '''
        name = request.form.get('name')
        pwd = request.form.get('pwd')
        if 'alex' == name and '123' == pwd:
            session['user_info'] = name
            return redirect('/index')
        else:
            # return render_template('login.html',msg='用户名或密码错误')
            return render_template('login.html',**{'msg':'用户名或密码错误'})

@app.route('/index',methods=['GET'])
def index():
    if not session.get('user_info'):
        return redirect('/login')
    response = make_response("这是首页")
    return response

if __name__ == '__main__':
    app.run()

  

Flask 装饰器登录session验证demo

import functools 

def auth(func):
	@functools.wraps(func)
	def inner(*args,**kwargs):
		user_info = session.get('user_info')
	    if not user_info:
	        return redirect('/login')
		return func(*args,**kwargs)
	return inner

# @app.route('/index',methods=['GET'],endpoint='n1')
@app.route('/index',methods=['GET'])
@auth
def index():
    return render_template('index.html')

  

  

参考:http://www.cnblogs.com/wupeiqi/articles/7552008.html

Flask官网:http://flask.pocoo.org/docs/0.10/

Flask中文版指南:http://docs.jinkan.org/docs/flask/

 

posted @ 2018-02-27 00:19  lixin[at]hitwh  阅读(201)  评论(0编辑  收藏  举报