1 Django:重武器,內部包含了很是多組件:ORM、Form、ModelForm、緩存、Session、中間件、信號等... html
2 Flask:短小精悍,內部沒有太多組件。第三方組件很是豐富。 路由比較特殊:基於裝飾器來實現,可是究其本質仍是經過add_url_rule來實現。前端
3 Tornado:異步非阻塞框架 ,底層使用的是 IOLoop 使用協程實現的異步非阻塞python
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)
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()
他們的本質都是基於sokectmysql
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()
pip3 install 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()
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':"高中的時候有一個同窗家裏窮,每頓飯都是膜膜加點水,有時候吃點鹹菜,咱們六科老師天天下課都叫他去辦公室回答問題背誦課文,而後說太晚啦一塊兒吃個飯,後來他考上了人大,拿到通知書的時候給每一個老師磕了一個頭"}, } def wrap(func): def inner(*args, **kwargs): user = session.get('user_info') if not user: return redirect('/login') return func() return inner @app.route('/detail/<int:nid>',methods=['GET'],endpoint='n1') # 登錄後才能訪問 @wrap def detail(nid): info = USERS.get(nid) return render_template('detail.html',info=info) @app.route('/index',methods=['GET'],endpoint='n2') # 登錄後才能訪問 @wrap 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()
<!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>
<!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>
<!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>
登錄設置sessionlinux
http://127.0.0.1:5000/login
攜帶session 訪問主頁web
http://127.0.0.1:5000/index
攜帶session 訪問詳情頁正則表達式
http://127.0.0.1:5000/detail/1
flask中的配置文件是一個flask.config.Config對象(繼承字典),默認配置爲: { 'DEBUG': get_debug_flag(default=False), 是否開啓Debug模式 'TESTING': False, 是否開啓測試模式 'PROPAGATE_EXCEPTIONS': None, 'PRESERVE_CONTEXT_ON_EXCEPTION': None, 'SECRET_KEY': None, 'PERMANENT_SESSION_LIFETIME': timedelta(days=31), 'USE_X_SENDFILE': False, 'LOGGER_NAME': None, 'LOGGER_HANDLER_POLICY': 'always', 'SERVER_NAME': None, 'APPLICATION_ROOT': None, 'SESSION_COOKIE_NAME': 'session', 'SESSION_COOKIE_DOMAIN': None, 'SESSION_COOKIE_PATH': None, 'SESSION_COOKIE_HTTPONLY': True, 'SESSION_COOKIE_SECURE': False, 'SESSION_REFRESH_EACH_REQUEST': True, 'MAX_CONTENT_LENGTH': None, 'SEND_FILE_MAX_AGE_DEFAULT': timedelta(hours=12), 'TRAP_BAD_REQUEST_ERRORS': False, 'TRAP_HTTP_EXCEPTIONS': False, 'EXPLAIN_TEMPLATE_LOADING': False, 'PREFERRED_URL_SCHEME': 'http', 'JSON_AS_ASCII': True, 'JSON_SORT_KEYS': True, 'JSONIFY_PRETTYPRINT_REGULAR': True, 'JSONIFY_MIMETYPE': 'application/json', 'TEMPLATES_AUTO_RELOAD': None, } 方式一: app.config['DEBUG'] = True PS: 因爲Config對象本質上是字典,因此還可使用app.config.update(...) 方式二: app.config.from_pyfile("python文件名稱") 如: settings.py DEBUG = True app.config.from_pyfile("settings.py") app.config.from_envvar("環境變量名稱") 環境變量的值爲python文件名稱名稱,內部調用from_pyfile方法 app.config.from_json("json文件名稱") JSON文件名稱,必須是json格式,由於內部會執行json.loads app.config.from_mapping({'DEBUG':True}) 字典格式 app.config.from_object("python類或類的路徑") app.config.from_object('pro_flask.settings.TestingConfig') settings.py class Config(object): DEBUG = False TESTING = False DATABASE_URI = 'sqlite://:memory:' class ProductionConfig(Config): DATABASE_URI = 'mysql://user@localhost/foo' class DevelopmentConfig(Config): DEBUG = True class TestingConfig(Config): TESTING = True PS: 從sys.path中已經存在路徑開始寫 PS: settings.py文件默認路徑要放在程序root_path目錄,若是instance_relative_config爲True,則就是instance_path目錄
在根目錄下建立config.pysql
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.pyjson
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()
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 添加路由的,基於這個咱們能夠模仿 flask
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()
from flask import Flask app = Flask(__name__) @app.route('/index/',methods=['GET','POST'],endpoint='n1',redirect_to="/index2",) def index():return '公司老首頁' @app.route('/index2/',methods=['GET','POST'],endpoint='n2',defaults={'nid':888},strict_slashes=True) def index2(nid): print(nid) return '公司新首頁' if __name__ == '__main__': app.run()
訪問公司的內部網站有時須要修改hosts文件
小工具:腳本 py文件【爲公司測試人員開發的修改host文件的小程序】
1 windows C:\Windows\System32\drivers\etc\hosts
2 linux /etc/hosts
添加如下的實例
127.0.0.1:5000 www.baidu.com
子域名訪問
在hosts文件中添加一個域名
127.0.0.1 zhangbiao.com 127.0.0.1 admin.zhangbiao.com 127.0.0.1 buy.zhangbiao.com
子域名訪問的代碼以下
from flask import Flask, views, url_for app = Flask(import_name=__name__) app.config['SERVER_NAME'] = 'zhangbiao.com:5000' @app.route("/", subdomain="admin") 返回靜態的子域名 def static_index(): """Flask supports static subdomains This is available at static.your-domain.tld""" return "xxxxxx.your-domain.tld" @app.route("/dynamic", subdomain="<username>") # 返回動態的子域名 def username_index(username): """Dynamic subdomains are also supported Try going to user1.your-domain.tld/dynamic""" print(username) return username + ".your-domain.tld" if __name__ == '__main__': app.run()
輸入子域名
http://admin.zhangbiao.com:5000/
返回靜態子域名以下
輸入子域名
http://buy.zhangbiao.com:5000/dynamic
返回動態子域名以下
基本的步奏
1 寫一個類 BaseConverter
2 視狀況而定,是否要重構 to_python 和 to_url方法
to_python 正則匹配成功以後,傳入視圖函數以前對先匹配的數據,進行二次處理
to_url 反向生成執行to_url ,在下面實例中在執行url_for的時候執行to_url
from flask import Flask, views, url_for from werkzeug.routing import BaseConverter app = Flask(import_name=__name__) # 1. 寫RegexConverter類 class RegexConverter(BaseConverter): """ 自定義URL匹配正則表達式 """ def __init__(self, map, regex): super(RegexConverter, self).__init__(map) self.regex = regex def to_python(self, value): """ 路由匹配時,匹配成功後傳遞給視圖函數中參數的值 :param value: :return: """ # "123" return int(value) def to_url(self, value): """ 使用url_for反向生成URL時,傳遞的參數通過該方法處理,返回的值用於生成URL中的參數 :param value: :return: """ val = super(RegexConverter, self).to_url(value) return val # 2. 將RegexConverter添加到flask中 app.url_map.converters['regex'] = RegexConverter @app.route('/index/<regex("\d+"):nid>') def index(nid): print(nid,type(nid)) url_for('index',nid=89) return 'Index' if __name__ == '__main__': app.run()
1 Flask 能夠傳遞函數給模板 2 後端對html進行轉義可使用markup 前端能夠用safe
2 減小前端代碼的複用,前端能夠定義宏,能夠像一個函數同樣調用
主程序
from flask import Flask,render_template,Markup,jsonify,make_response app = Flask(__name__) def func1(arg): return Markup("<input type='text' value='%s' />" %(arg,)) @app.route('/') def index(): # return jsonify({'k1':'v1'}) return render_template('s10index.html',ff = func1) if __name__ == '__main__': app.run()
s10index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {{ff('六五')}} {% macro xx(name, type='text', value='') %} <input type="{{ type }}" name="{{ name }}1" value="{{ value }}"> <input type="{{ type }}" name="{{ name }}2" value="{{ value }}"> <input type="{{ type }}" name="{{ name }}3" value="{{ value }}"> <input type="{{ type }}" name="{{ name }}4" value="{{ value }}"> {% endmacro %} {{ xx('n') }} </body> </html>
請求封裝在 request中
from flask import Flask,request
響應
from flask import Flask,jsonify,make_response
from flask import Flask,jsonify,make_response,request app = Flask(__name__) @app.route('/') def index(): response = make_response("asdfasdf") response.set_cookie("name", 'zhang') return response if __name__ == '__main__': app.run()
簡單的使用以下
from flask import Flask,session app = Flask(__name__) app.secret_key = 'sdfsdf' @app.route('/') def set_session(): # flask內置的使用 加密cookie(簽名cookie)來保存數據。 session['k1'] = 'v1' session['k2'] = 'v2' return 'xxx' @app.route('/get_session') def get_session(): # flask內置的使用 加密cookie(簽名cookie)來保存數據。 k1=session.get('k1','') print(k1) return 'xxx' if __name__ == '__main__': app.run()