flask之三:視圖高級

視圖高級

app.routeapp.add_url_rule

  • app.add_url_rule
app.add_url_rule('/list/',endpoint='myweb',view_func=my_list)

這個方法是用來添加url視圖函數的映射。若是沒有填寫endpoint那麼會默認使用view_func的名字來做爲endpoint
所以在使用url_for的時候,就要看在映射的時候有沒有傳遞endpoint參數,若是傳遞了,那麼就使用endpoint指定的字符串。
付過沒有使用的話就使用view_func定義的名字。css

  • app.route(rule,**options)裝飾器

這個裝飾器的底層就是用add_url_rule來實現url與視圖函數映射的。html

  • 小例子以下:
from flask import Flask,url_for
app = Flask(__name__)
app.config.update({
    'DEBUG':True,
    'TEMPLATES_AUTO_RELOAD':True
})
@app.route('/',endpoint='index')
def hello_world():
    print(url_for('myweb'))
    return 'Hello World!'
def my_list():
    return 'list page!'
app.add_url_rule('/list/',endpoint='myweb',view_func=my_list)
#請求上下文的定義,結合url_for
with app.test_request_context():
    print(url_for('index'))
if __name__ == '__main__':
    app.run()

類視圖

以前咱們接觸的視圖都是函數,因此通常簡稱視圖函數。
其實視圖也能夠基於類來實現,類視圖的好處是支持繼承,可是類視圖不能跟函數視圖同樣,
寫完類視圖還須要經過app.add_url_rule(url_rule,view_func)來進行註冊。如下將對兩種類視圖進行講解python

標準視圖

  1. 標準類視圖必須繼承自flask.views.View
  2. 必須實現dispatch_request方法,之後請求過來之後,會執行這個方法。這個方法的返回值就至關因而以前的函數視圖同樣,也必須返回Request或者子類的對象(字符串或者元組)。
  3. 必須是經過app.add_url_rule(rule,endpoint,view_func)來作url映射。

view_func這個參數,要使用as_view這個方法來轉換web

  1. 若是指定了endpoint,那麼在使用url_for反轉的時候,就要使用endpoint指定的那個值,若是沒有指定那個值,就使用as_view中指定的視圖名字來做爲反轉。
  2. 類視圖有如下的好處,能夠將一些共性的東西抽取出來放到父視圖中,子視圖直接繼承就能夠了,可是也不是說全部的視圖都要使用類視圖,這個要根據實際狀況來定。
  • 小例子:
from flask import Flask,views,url_for
app = Flask(__name__)
class ListView(views.View):
    def dispatch_request(self):
        return 'list view'
#app.add_url_rule('/list/',endpoint='list',view_func=ListView.as_view('list'))
app.add_url_rule('/list/',view_func=ListView.as_view('list'))
with app.test_request_context():
    print(url_for('list'))
@app.route('/')
def hello_world():
    return 'Hello World!'
if __name__ == '__main__':
    app.run(debug=True)
  • 類視圖的小例子:
from flask import Flask,url_for,views,jsonify,render_template

app = Flask(__name__)
app.config.update({
    'DEBUG':True,
    'TEMPLATES_AUTO_RELOAD':True
})

#自定義封裝,返回json數據
class JSONView(views.View):
    def get_data(self):
        raise NotImplementedError
    def dispatch_request(self):
        return jsonify(self.get_data())

class ListView(JSONView):
    def get_data(self):
        return {
            'username':'wanghui',
            'password':123456,
        }

app.add_url_rule('/list/',endpoint='my_list',view_func=ListView.as_view('list'))
#有幾個視圖,須要返回相同的變量(廣告頁面)
class ADSView(views.View):
    def __init__(self):
        super(ADSView, self).__init__()
        self.context = {
            'ads':"今年過節不收禮,收禮只收腦白金"
        }
class RegistView(ADSView):
    def dispatch_request(self):
        self.context.update({'username':'abcd'})
        return render_template('register.html',**self.context)
class LoginView(ADSView):
    def dispatch_request(self):
        return render_template('login.html',**self.context)
# class LoginView(views.View):
#     def dispatch_request(self):
#         return render_template('login.html',ads="今年過節不收禮,收禮只收腦白金")
# class RegistView(views.View):
#     def dispatch_request(self):
#         return render_template('register.html',ads="今年過節不收禮,收禮只收腦白金")
app.add_url_rule('/login/',view_func=LoginView.as_view('login'))
app.add_url_rule('/regist/',view_func=RegistView.as_view('regist'))

@app.route('/')
def hello():
    return "heello"
if __name__ == '__main__':
    app.run()

基於調度方法的視圖

  • 根據請求方法來執行不一樣的方法的,若是用戶發送的是get請求,就會執行這個類的get方法;若是用戶發起的是post方法,就會執行這個類的post方法。其餘的方法相似,這種方法使得代碼更加簡潔,使得執行get請求的代碼放在get方法中,post請求的代碼放在posy方法中。就不須要跟以前的request.method == 'POST'來搞了。
  • 小例子
  • py
from flask import Flask,views,render_template,request

app = Flask(__name__)

class LoginView(views.MethodView):
    def __render(self,error=None):
        return render_template('login.html',error=error)
    def get(self,error=None):
        # return render_template('login.html',error=error)
        return self.__render()
    def post(self):
        username = request.form.get('username')
        password = request.form.get('password')
        if username == 'wanghui' and password == '111111':
            return 'login success'
        else:
            # return render_template('login.html',error="username or password error,retry!")
            # return self.get(error="username or password error,retry!")
            return self.__render(error="username or password error,retry!")

app.add_url_rule('/login/',view_func=LoginView.as_view('login'))

@app.route('/')
def hello_world():
    return 'Hello World!'

if __name__ == '__main__':
    app.run(debug=True,port=9090)
  • login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login</title>
</head>
<body>
<form action="" method="post">
    <table>
        <tr>
            <td>用戶名</td>
            <td><input type="text" name="username"></td>
        </tr>
        <tr>
            <td>密碼</td>
            <td><input type="password" name="password"></td>
        </tr>
        <tr>
            <td></td>
            <td><input type="submit" value="當即登錄"></td>
        </tr>
    </table>
    {% if error %}
        <p style="color: red;">{{ error }}</p>

    {% endif %}
</form>
</body>
</html>

類視圖上面使用裝飾器

兩種類型的裝飾器json

  1. 若是使用的是函數視圖, 那麼定義的裝飾器必須放在app.route下面,不然起不到任何做用
  1. 類視圖的裝飾器,須要重寫類視圖的decorators類屬性,裏面裝的就是全部的裝飾器
  • 小例子:
from flask import Flask,request,views
from functools import wraps

app = Flask(__name__)

#定義裝飾器
def login_required(func):
    @wraps(func)
    def wrapper(*args,**kwargs):
        username = request.args.get('username')
        if username and username == 'wanghui':
            return func(*args,**kwargs)
        else:
            return "請先登陸"
    return wrapper


@app.route('/settings/')
@login_required
def settings():
    return '這是設置頁面'

#這樣請求就行http://127.0.0.1:9091/settings/?username=wanghui

#類視圖添加裝飾器
class ProfileView(views.View):
    decorators = [login_required]
    def dispatch_request(self):
        return "這是我的中心"
app.add_url_rule('/profile/',view_func=ProfileView.as_view('profile'))

藍圖

將大型項目分層解耦,實現模塊化,結構更加清晰。能夠將相同的模塊放在同一個藍圖下,同一個文件夾中。方便管理。
  • 基本語法:
  1. 在藍圖文件中導入Blueprint
from flask import Blueprint
user_bp = Blueprint('user',__name__)    #至關因而定義`app = Flask(__name__)`
  1. 在主app文件中註冊藍圖
from blueprints.user import user_bp
app.regist_blueprint(user_bp)   #實現註冊藍圖
  1. 若是想要某個藍圖下的全部URL的時候有個前綴,那麼能夠在定義藍圖的時候加上url_prefix
from flask import Blueprint
user_bp = Blueprint('user',__name__,url_prefix='/user') 
# 特別注意斜槓

藍圖中的模板文件

  • 藍圖模板文件查找:flask

    • 若是項目中的templates文件夾中存在對應的模板文件,就能夠直接使用
    • 若是項目中的templates文件夾中存在相應的模板文件,那麼就在定義藍圖的指定路徑中查找,能夠設置相對路徑,就要在藍圖文件相同路徑下的文件夾。
from flask import Blueprint,render_template
news_bp = Blueprint('news',__name__,url_prefix='/news',template_folder='news')
@news_bp.route('/list/')
def news_list():
    return render_template('news_list.html')
  • 藍圖中的靜態文件查找:app

    • 在模板文件中,加載靜態文件,若是使用url_for('static'),那麼只會在app指定的靜態文件夾目錄下查找靜態文件
    • 若是在加載靜態文件的時候置頂了藍圖的名字,好比url_for('news.static'),那麼會到藍圖指定的static_folder下查找靜態文件。

url_for反轉藍圖注意事項

  • 注意url_for到藍圖中的視圖函數的時候,要反轉藍圖中的視圖函數爲url,那麼就用該在使用url_for的時候使用url_for('news.news_list')否則就找不到這個endpoint。
  • 即便在同一個藍圖中,反轉視圖函數,也要制定藍圖的名字

子域名實現

  1. 使用藍圖技術
  2. 在建立藍圖對象的時候要使用subdomain來指定這個子域名
from flask import Blueprint
cms_bp = Blueprint('cms',__name__,subdomain='cms')
  1. 須要在app文件中配置app.config['SERVER_NAME']='baidu.com'來指定跟域名
app.config['SERVER_NAME'] = 'crop.com:9099'
  1. 修改hosts文件配置解析
127.0.0.1 crop.com
127.0.0.1 cms.crop.com

5.訪問dom

cms.crop.com:9099

綜合實例代碼

  • 目錄結構
blue_print_e
├── blue_print_e.py
├── blueprints
│ ├── bok.py
│ ├── cms.py
│ ├── movie.py
│ ├── news_css
│ │ └── news_list.css
│ ├── news.py
│ ├── news_tmp
│ │ └── news_list.html
│ └── user.py
├── static
│ └── news_list.css
└── templates
    ├── index.html
    └── news_list.html
  • 主app文件blue_print_e.py
from flask import Flask,url_for,render_template
from blueprints.user import user_bp
from blueprints.news import news_bp
from blueprints.cms import cms_bp

app = Flask(__name__)
app.config['SERVER_NAME'] = 'crop.com:9099'

app.register_blueprint(user_bp)
app.register_blueprint(news_bp)
app.register_blueprint(cms_bp)
# ip地址不能有子域名
@app.route('/')
def hello_world():
    print(url_for('news_tmp.news_list'))     #使用藍圖名字.視圖函數的名字
    return render_template('index.html')
if __name__ == '__main__':
    app.run(debug=True,port=9099)
  • blueprints/news.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from flask import Blueprint,render_template,url_for

news_bp = Blueprint('news_tmp',__name__,url_prefix='/news_tmp',template_folder='news_tmp',static_folder='news_css')

@news_bp.route('/list/')
def news_list():
    print(url_for('news.news_detail'))
    return render_template('news_list.html')

@news_bp.route('/detail')
def news_detail():
    return "詳情頁面"
  • blueprints/user.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from flask import Blueprint

user_bp = Blueprint('user',__name__,url_prefix='/user')
@user_bp.route('/profile/')
def profile():
    return "我的中心"

@user_bp.route('/settings/')
def settings():
    return "設置頁面"
  • blueprint/cms.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from flask import Blueprint
cms_bp = Blueprint('cms',__name__,subdomain='cms')
@cms_bp.route('/')
def index():
    return 'cms index'
  • blueprints/news_css/
body {
    color: fuchsia;
    font-size: 90px;
    background: red;
}
相關文章
相關標籤/搜索