Flask、Django、Tornado框架 区别
1 Django:重武器,内部包含了非常多组件:ORM、Form、ModelForm、缓存、Session、中间件、信号等...
2 Flask:短小精悍,内部没有太多组件。第三方组件非常丰富。 路由比较特殊:基于装饰器来实现,但是究其本质还是通过add_url_rule来实现。
3 Tornado:异步非阻塞框架 ,底层使用的是 IOLoop 使用协程实现的异步非阻塞
wsji
werkzeug示例
from werkzeug.wrappers import Request, Response @Request.application def hello(request): return Response('Hello World!') if __name__ == '__main__': from werkzeug.serving import run_simple run_simple('localhost', 4000, hello)
wsgiref示例
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__': # obj = WSGIHandler() httpd = make_server('', 8000, runserver) httpd.serve_forever()
他们的本质都是基于sokect
import socket def handle_request(client): buf = client.recv(1024) client.send("HTTP/1.1 200 OK\r\n\r\n") client.send("Hello, Seven") def main(): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(('localhost',8000)) sock.listen(5) while True: connection, address = sock.accept() handle_request(connection) connection.close() if __name__ == '__main__': main()
安装 Flask
pip3 install flask
创建一个简单的Flask 程序
from flask import Flask # 实例化Flask对象 app = Flask(__name__) # 将 '/' 和 函数index的对应关系添加到路由中。 """ { ‘/’:index } """ @app.route('/') def index(): return 'Hello World!' if __name__ == '__main__': # 监听用户请求 # 如果有用户请求到来,则执行app的__call__方法 app.__call__ app.run()
通过写一个简单的登陆小案例来了解Flask的使用
from flask import Flask,render_template,request,redirect,session,url_for app = Flask(__name__) app.debug = True app.secret_key = 'siuljskdjfs' USERS = { 1:{'name':'张桂坤','age':18,'gender':'男','text':"当眼泪掉下来的时候,是真的累了, 其实人生就是这样: 你有你的烦,我有我的难,人人都有无声的泪,人人都有难言的苦。 忘不了的昨天,忙不完的今天,想不到的明天,走不完的人生,过不完的坎坷,越不过的无奈,听不完的谎言,看不透的人心放不下的牵挂,经历不完的酸甜苦辣,这就是人生,这就是生活。"}, 2:{'name':'主城','age':28,'gender':'男','text':"高中的时候有一个同学家里穷,每顿饭都是膜膜加点水,有时候吃点咸菜,我们六科老师每天下课都叫他去办公室回答问题背诵课文,然后说太晚啦一起吃个饭,后来他考上了人大,拿到通知书的时候给每个老师磕了一个头"}, 3:{'name':'服城','age':18,'gender':'女','text':"高中的时候有一个同学家里穷,每顿饭都是膜膜加点水,有时候吃点咸菜,我们六科老师每天下课都叫他去办公室回答问题背诵课文,然后说太晚啦一起吃个饭,后来他考上了人大,拿到通知书的时候给每个老师磕了一个头"}, } @app.route('/detail/<int:nid>',methods=['GET']) # 登陆后才能访问 def detail(nid): user = session.get('user_info') if not user: return redirect('/login') info = USERS.get(nid) return render_template('detail.html',info=info) @app.route('/index',methods=['GET']) # 登陆后才能访问 def index(): user = session.get('user_info') print(user) if not user: # return redirect('/login') url = url_for('l1') return redirect(url) return render_template('index.html',user_dict=USERS) @app.route('/login',methods=['GET','POST'],endpoint='l1') def login(): if request.method == "GET": return render_template('login.html') else: # request.query_string user = request.form.get('user') pwd = request.form.get('pwd') if user == 'zhang' and pwd == '123': session['user_info'] = user return redirect('http://www.baidu.com') return render_template('login.html',error='用户名或密码错误') if __name__ == '__main__': app.run()
创建登陆模板 templates/login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>用户登录</h1> <form method="post"> <input type="text" name="user"> <input type="text" name="pwd"> <input type="submit" value="登录">{{error}} </form> </body> </html>
创建首页模板 templates/index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>用户列表</h1> <table> {% for k,v in user_dict.items() %} <tr> <td>{{k}}</td> <td>{{v.name}}</td> <td>{{v['name']}}</td> <td>{{v.get('name')}}</td> <td><a href="/detail/{{k}}">查看详细</a></td> </tr> {% endfor %} </table> </body> </html>
创建详情页模板 templates/detail.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>详细信息 {{info.name}}</h1> <div> {{info.text}} </div> </body> </html>
登陆设置session
http://127.0.0.1:5000/login
扫描二维码关注公众号,回复:
3026627 查看本文章
携带session 访问主页
http://127.0.0.1:5000/index
携带session 访问详情页
http://127.0.0.1:5000/detail/1
配置文件
在根目录下创建config.py
class Config(object): DEBUG = False TESTING = False secret_key = "asdfasdf" DATABASE_URI = 'sqlite://:memory:' class ProductionConfig(Config): DATABASE_URI = 'mysql://user@localhost/foo' class DevelopmentConfig(Config): DEBUG = True
创建s3.py ,引入配置文件 config.py
from flask import Flask from config import DevelopmentConfig app = Flask(__name__) app.config.from_object(DevelopmentConfig) @app.route('/') def index():return 'Hello World!' if __name__ == '__main__': app.run()
Flask 中路由的本质
1. decorator = app.route('/',methods=['GET','POST'],endpoint='n1') def route(self, rule, **options): # app对象 # rule= / # options = {methods=['GET','POST'],endpoint='n1'} def decorator(f): endpoint = options.pop('endpoint', None) self.add_url_rule(rule, endpoint, f, **options) return f return decorator 2. @decorator ----> index = decorator(index) decorator(index)
通过源码我们可以看到最终是通过 add_url_rule 添加路由的,基于这个我们可以模仿
from flask import Flask app = Flask(__name__) def login(): return '登录' app.add_url_rule('/login', 'n2', login, methods=['GET',"POST"]) if __name__ == '__main__': app.run(
类视图
之前使用的视图都是函数,简称为视图函数,视图也可以基于类来实现,类视图的好处是支持继承,类视图需要通过app.add_url_role(url_rule,view_func(name="必传的参数"))来进行注册,类里面要加装饰器就用:detactors=[] ,里面可以添加多个装饰器
可以设置类属性来做一些限制 methods 可以限制访问的请求方法 , decorators 增加装饰器
from flask import Flask,views app = Flask(__name__) app.debug = True app.secret_key = "asdfasdf" def auth(func): def inner(*args, **kwargs): result = func(*args, **kwargs) return result return inner class IndexView(views.MethodView): methods = ['GET'] # 只允许GET 请求访问 decorators = [auth, ] # 添加装饰器 def get(self): return 'Index.GET' def post(self): return 'Index.POST' app.add_url_rule('/index', view_func=IndexView.as_view(name='index')) # name=endpoint if __name__ == '__main__': app.run()