Flask 快速使用 —— (1)

 Flask、Django、Tornado框架 區別 

  1  Django:重武器,內部包含了很是多組件:ORM、Form、ModelForm、緩存、Session、中間件、信號等... html

  2   Flask:短小精悍,內部沒有太多組件。第三方組件很是豐富。 路由比較特殊:基於裝飾器來實現,可是究其本質仍是經過add_url_rule來實現。前端

  3   Tornado:異步非阻塞框架 ,底層使用的是 IOLoop 使用協程實現的異步非阻塞python

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()

 

 他們的本質都是基於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()

安裝 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':"高中的時候有一個同窗家裏窮,每頓飯都是膜膜加點水,有時候吃點鹹菜,咱們六科老師天天下課都叫他去辦公室回答問題背誦課文,而後說太晚啦一塊兒吃個飯,後來他考上了人大,拿到通知書的時候給每一個老師磕了一個頭"},
}

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()

 

 

建立登錄模板  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>

 登錄設置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()

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  添加路由的,基於這個咱們能夠模仿  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()

add_url_rule中的參數介紹

一個簡單的重定向的小實例

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()

  

Session

簡單的使用以下

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()
相關文章
相關標籤/搜索