Flask-論壇開發-4-知識點補充

對Flask感興趣的,能夠看下這個視頻教程:http://study.163.com/course/courseLearn.htm?courseId=1004091002html

1. WTForms 表單使用

WTForms 是一個支持多 web 框架的一個插件,主要功能有兩個:第一個是作表單的驗證,驗證用戶提交上來的信息是否合法,第二個是模板渲染。前端

1.1 WTForms 表單驗證的基本使用

使用 WTForms 進行表單驗證,會更好的管理咱們的代碼和項目結構,還能夠大大提升開發項目時的效率。WTForms 功能強大,將表單定義成一個類,能夠實現對錶單字段的豐富限制。python

使用 WTForms 實現表單驗證的功能,主要有如下步驟:web

  1. wtforms 中導入 Form 這個類,以及相關字段的數據類型正則表達式

    from wtforms import From,StringField,IntegerField,FileField
    
     # Form 是一個基類,StringField 用來驗證 String 類型的數據
  2. wrforms.validators 導入一些限制對象(如長度限制)json

    from wrforms.validators import Length,EqualTo
    
     # # wrforms.vaildators 是一個驗證器,包含 Length 在內的多種驗證限制,Length 則專門對參數的長度進行驗證,EqualTo 指定必需要和某個值相等
  3. 建立表單類並繼承自 Form,定義相關字段flask

    class RegistForm(Form):     # 該類用來驗證表單中傳遞的參數,屬性名和參數名必須一致
         username = StringField(validators=[Length(min=3,max=10,message='用戶名長度必須在3到10位之間')])   
         # StringField 必須傳入關鍵字參數 validators,且 validators 是一個 List 類型(此處僅對長度做驗證)
         password = StringField(validators=[Length(min=6,max=16)])
         password_repeat = StringField(validators=[Length(min=6,max=16),EqualTo('password')])    # 驗證長度和相等
  4. 在視圖函數中使用該 RegistForm後端

    form = RegistForm(request.form)     # request.form 會拿到全部提交的表單信息
     if form.validate():     # form.validate() 方法會匹配表單信息並返回 True 或 False
         return '註冊成功!'
     else:
         return '註冊失敗!'

完整代碼以下:api

# regist.html
<form action="" method="post">
    <table>
        <tbody>
            <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="password" name="password_repeat"></td>
            </tr>
            <tr>
                <td></td>
                <td><input type="submit" value="點擊提交"></td>
            </tr>
        </tbody>
    </table>
</form>

# 後端程序
from wtforms import Form,StringField
from wtforms.validators import Length,EqualTo

class RegistForm(Form):
    username = StringField(validators=[Length(min=3,max=10,message='輸入的用戶名不符合長度規範')])
    password = StringField(validators=[Length(min=6,max=16)])
    password_repeat = StringField(validators=[Length(min=6,max=16),EqualTo('password')])

@app.route('/regist/',methods=['GET','POST'])
def regist():
    if request.method == 'GET':
        return render_template('regist.html')
    else:
        form = RegistForm(request.form)
        if form.validate():
            return '註冊成功'
        else:
            print(form.errors)
            for message in form.errors:
                return '註冊成功'

1.2 WTForms 的相關驗證器

除了上面使用到的兩個驗證器(StringFieldEqualTo)外,WTForms 中還有不少經常使用的驗證器:瀏覽器

  1. Email:驗證上傳的數據是否爲郵箱(格式)

    email = StringField(validators=[email()])
  2. EqualTo:驗證上傳的數據是否與另外一個字段相等,經常使用在註冊時的兩次密碼輸入上

    password_repeat = StringField(validators=[Length(min=6,max=16),EqualTo('password')])
  3. InputRequired:該字段必須輸入參數,且只要輸入了,那麼該字段就是 True。若是不是特數據狀況,應該使用 InputRequired

    password = StringField(validators=[InputRequired()])    # 無論你的值是什麼,只要輸入了就是 True
  4. Length:長度限制,由 minmax 兩個值進行限制

    password = StringField(validators=[Length(6,16)])
  5. NumberRange:數字的區間,由 minmax 兩個值進行限制(包括 minmax)

    age = IntegerField(validators=[NumberRange(12,100)])
  6. Regexp:自定義正則表達式,好比手機號碼的匹配

    phone = StringField(validators=[Regexp(r'1[34578]\d{9}')])
  7. URL:必需要是 URL 的形式

    homepage = StringField(validators=[URL()])
  8. UUID:驗證 UUID

    uuid = StringField(validators=[UUID()])

注意在使用驗證器的時候,後面要加上 ()

1.3 自定義驗證器

若是以上介紹的驗證器不知足項目當中的需求,那麼還能夠根據需求自定義相關的驗證器。若是想要對錶單中的某個字段進行更加細緻的驗證,那麼能夠根據需求對該字段定進行單獨的驗證,步驟以下:

  1. 在表單驗證類中定義一個方法,方法的命名規則爲:validate_字段名(self,field)
  2. 在方法中使用 field.data 獲取到用戶上傳到這個字段上的值。
  3. 對於驗證的判斷:若驗證成功,能夠什麼都不作;若驗證失敗,則必須跑出 wtforms.validators.ValidationError 異常,並填入驗證失敗的緣由。

示例代碼以下所示:

from wtforms import Form,StringField
from wtforms.validators import Length,ValidationError

class LoginForm(Form):
    captcha = StringField(validators=[Length(4,4)])
    def validate_captcha(self,field):   # 用 validate_captcha 來指定該驗證器是針對 captcha 字段的
        if field.data != 'aw7e':
            raise ValidationError('驗證碼輸入錯誤!')

1.4 WTForms 渲染模板

這個功能可讓咱們的前端代碼少寫一點點,可是實際上用處不大。主要使用方法以下:

  1. forms 文件中定義一個表單類:

    class SettingsForms(Form):
         username = StringField(validators=[Length(4,10)])
  2. 在視圖函數中返回模板時傳遞相關參數:

    @app.route('/settings/',methods=['GET','POST'])
     def Settings():
         if request.method == 'GET':
             form = SettingsForms()
             return render_template('settings.html',my_form=form)
         else:
             pass
  3. 在前端模板中調用

    <form action="" method="post">
         <table>
             <tbody>
                 <tr>
                     <td>{{ my_form.username.label }}</td>
                     <td>{{ my_form.username() }}</td>
                 </tr>
                 <tr>
                     <td></td>
                     <td><input type="submit" value="提交"></td>
                 </tr>
             </tbody>
         </table>
     </form>

    其中,第五第六兩行至關於:

    <td>用戶名:</td>
     <td><input type="text" name='username'></td>

實際上,這個功能在生產環境中幾乎沒有任何做用,很雞肋。

2. 文件上傳和訪問

2.1 文件上傳

上傳文件時須要注意如下幾點:

  1. 在模板中,form 表單內,要指定 encotype='multipart/form-data' 才能實現文件的上傳:

    <form action="" method="post" enctype="multipart/form-data">
         ...
     </form>
  2. 在後臺獲取文件,須要使用 request.files.get('標籤名') 才能獲取到上傳的文件:

    avatar = request.files.get('avatar')
  3. 保存文件使用 avatar.save(路徑) 實現,推薦在保存文件時先對文件進行安全封裝:

    from werkzueg.utils import secure_filename
     import os
    
     UPLOAD_PATH = os.path.join(os.path.dirname(__file__),'images')  # UPLOAD_PATH = 當前路徑/images
    
     avatar.save(UPLOAD_PATH,secure_filename(avatar.filename))
  4. 後臺完整代碼以下:

    from werkzeug.utils import secure_filename
     import os
    
     UPLOAD_PATH = os.path.join(os.path.dirname(__file__),'images')  # 定義文件保存路徑:UPLOAD_PATH = 當前路徑/images
    
     @app.route('/upload/',methods=['GET','POST'])
     def upload():
         if request.method == 'GET':
             return render_template('upload.html')
         else:
             avatar = request.files.get('avatar')
             filename = secure_filename(avatar.filename)     # 對文件名進行安全過濾
             avatar.save(os.path.join(UPLOAD_PATH,filename))
             desc = request.form.get('desc')
             print(desc)
             return '上傳成功!'

2.2 文件訪問

實現了文件上傳,那麼用戶確定會須要對文件進行訪問。在 Flask 中,實現文件的訪問必需要定義一個單獨的 url 與視圖函數的映射,而且要藉助 send_from_directory 方法返回文件給客戶端。

  1. flask 導入 send_from_directory

    from flask import send_from_directory
  2. 定義視圖函數並映射到文件的 url

    UPLOAD_PATH = os.path.join(os.path.dirname(__file__),'images')
    
     @app.route('/getfile/<filename>/')
     def getfile(filename):
         return send_from_directory(UPLOAD_PATH,filename)    # send_from_directory 要傳入路徑和文件名
    
     # 用戶能夠訪問 http://domainname/filename 對文件進行訪問

2.3 使用驗證器對驗證上傳的文件

在驗證文件的時候,一樣要定義一個驗證的類,而後用該驗證類去驗證上傳的文件。主要分爲如下幾個步驟:

  1. 導入 FileField 和文件驗證器:FileRequiredFileAllowed

    from forms import FileField
     from flask_wtf.file import FileRequired,FileAllowed     # 注意這兩個針對文件的驗證器是從 flask_wtf_file 中導入的,而不是從以前的 wtforms.validators 中導入
  2. 定義表單類並繼承自 Form,而後定義相關字段

    class UpLoadForm(Form):
         avatar = FileField(validators=[FileRequired(),FileAllowed(['jpg','png','gif'])])        # FileRequired() 要求必須傳入文件,FileAllowed() 則指定了容許的文件類型
         desc = StringField(validators=[InputRequired()])
  3. 在主 app 文件中引用

    from werkzeug.datastructures import CombinedMultiDict   # CombinedMultiDict 用來合併兩個不可變的 dict
     form =UpLoadForm(CombinedMultiDict([request.form,request.files]))   # 傳入用戶提交的信息,其中 request.form 是表單中的信息,request.files 是上傳的文件
  4. 完整代碼以下:

    # forms.py 文件
     from wtforms import Form,StringField,FileField
     from flask_wtf.file import FileRequired,FileAllowed
    
     class UpLoadForm(Form):
         avatar = FileField(validators=[FileRequired(),FileAllowed(['jpg','png','gif'])])
         desc = StringField(validators=[InputRequired()])
    
     # 主 app 文件
     from forms import UpLoadForm
     from werkzeug.utils import secure_filename
     from werkzeug.datastructures import CombinedMultiDict
     import os
    
     UPLOAD_PATH = os.path.join(os.path.dirname(__file__),'images')
    
     @app.route('/upload/',methods=['GET','POST'])
     def upload():
         if request.method == 'GET':
             return render_template('upload.html')
         else:
             form =UpLoadForm(CombinedMultiDict([request.form,request.files]))
             if form.validate():
                 avatar = request.files.get('avatar')
                 filename = secure_filename(avatar.filename)
                 avatar.save(os.path.join(UPLOAD_PATH,filename))
                 desc = request.form.get('desc')
                 print(desc)
                 return '上傳成功!'
             else:
                 return '上傳失敗!'

設置 CookieResponse 類中有的方法,用法是:在視圖函數中

resp = Response('MYYD')     # 建立一個 Response 對象,傳入的字符串會被顯示在網頁中
resp.set_cookie('username','myyd')
return resp

其中,set_cookie() 中的參數有:

key         鍵
value       值
max_age     IE8 如下不支持,優先級比 expires 高
expires     幾乎全部瀏覽器都支持,必須傳入 datetime 的數據類型,而且默認加 8 個小時(由於咱們是東八區)
path        生效的 URL,'/' 表明該域名下全部 URL 都生效,通常默認就好
domian      域名,若沒設置,則只能在當前域名下使用
secure      默認 False,若改成 True 則只能在 https 協議下使用
httponly    默認 False,若改成 True 則只能被瀏覽器所讀取,不能被 JavaScript 讀取(JavaScript能夠在前端處理一些簡單邏輯)

使用時依次傳入便可,若是有些選項要跳過則須要指定一下參數名。

完整代碼以下所示:

from flask import Flask,Response

app = Flask(__name__)


@app.route('/')
def hello_world():
    resp = Response('首頁')
    resp.set_cookie('username','MYYD')
    return resp

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

刪除 Cookie 時須要另外指定一條 URL 和視圖函數,也是使用 Response 來建立一個類,並使用 resp.delete_cookie() 來完成這個需求。代碼以下所示:

from flask import Flask,Response

app = Flask(__name__)

@app.route('/delCookie/')
def delete_cookie():
    resp = Response('刪除Cookie')
    resp.delete_cookie('username')
    return resp

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

設置 Cookie 的有效期,能夠有兩種方法:使用 max_ageexpires

  1. 使用 max_age

    使用 max-age 時要注意,max-age 不支持 IE8 及如下版本的瀏覽器,而且只能相對於如今的時間日後進行推遲(單位是秒s),而不能指定具體的失效時間。使用方法以下代碼所示:

    resp.set_cookie('username','myyd',max_age=60)   # 設置該 cookie 60s 以後失效。
  2. 使用 expires

    使用 expires 時要注意,必需要使用格林尼治時間,由於最後會自動加上 8 小時(中國是東八區)。expires 的兼容性要比 max_age 要好,儘管在新版的 http 協議中指明瞭 expires 要被廢棄,但如今幾乎全部的瀏覽器都支持 expires

    expire 設置失效時間,能夠針對當前時間日後推移,也能夠指定某一個具體的失效時間。具體以下所示:

    1. 針對當前時間推移

      from datetime import datetime,timedelta
      
       expires = datetime.now() + timedelta(days=30,hours=16)  # 當下時間日後推移 31 天失效,注意這裏給的參數是減了 8 小時的
       resp.set_cookie('username','MYYD',expires=expires)
    2. 指定具體日期

      from datetime import datetime
      
       resp = Response('首頁')
       expires = datetime(year=2018,month=12,day=30,hour=10,minute=0,second=0) # 實際上的失效時間是 2018-12-30-18:0:0
       resp.set_cookie('username','MYYD',expires=expires)
       return resp
  3. 其餘注意事項

    此外,還要注意幾點:

    1. 當同時使用 max_ageexpires 的時候,會優先使用 max_age 指定的失效時間
    2. 若同時不使用 max_ageexpires 的時候,默認的 cookie 失效時間爲瀏覽器關閉的時間(而不是窗口關閉的時間)
    3. expires 要設置爲格林尼治時間,同時導入 datetime.datetimedatetime.timedelta

4. RFCS

防範 CSRF 攻擊的措施:

實現:在返回一些危險操做的頁面時,同時返回一個 csrf_tokencookie 信息,而且在返回的頁面表單中也返回一個帶有 csrf_token 值的 input 標籤。

原理:當用戶提交該表單時,若表單中 input 標籤的 csrf_token 值存在而且和 cookie 中的 csrf_token 值相等則容許操做;若不知足該條件,則操做不被容許。

緣由:由於 csrf_token 這個值是在返回危險操做頁面時隨機生成的,黑客是沒法僞造出相同的 csrf_token 值的,由於黑客不能操做非本身域名下的 cookie,即不知道 cookie 中的 csrf_token 值的內容。

具體實現:

主app文件:

  1. from flask_wtf import CSRFProtect
  2. CSRFProtect(app)

模板文件(表單中):

<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
注意這裏是要在全部危險操做頁面的表單內都須要加入。

瀏覽器:F12 -> Network -> Disable Cache

// 整個文檔加載完畢後纔會執行這個函數
$(function () {
    $('#submit').click(function (event) {
        // 阻止默認的表單提交行爲
        // event.preventDefault();
        var email = $('input[name=email]').val();
        var password = $('input[name=password]').val();
        var csrftoken = $('input[name=csrf_token]').val();

        // $.post() 方法用來提交表單
        $.post({
            'url':'/login/',
            'data':{
                'email': email,
                'password': password,
                'csrftoken': csrftoken
            },
            'success':function (data) {
                console.log(data);
            },
            'fail':function (error) {
                console.log(error);
            }
        });
    })
});

5. Flask Restful

5.1 Restful API 介紹

Restful API 是用於在前端與後臺進行通訊時使用的一套傳輸規範,這些規範可使後臺開發變得更加輕鬆。

其採用的協議httphttps

傳輸數據格式採用 json 而不是 xml。使用 json 傳輸數據會變得更加簡單高效,而不是像 xml 那樣伴隨有衆多的固定代碼(相似於 html 的格式),即每次傳輸時 xml 佔的資源更多。

而且其url 連接中,不能包含動詞,只能包含名詞;而且對於名詞,若出現複數,則必須加上 s

HTTP 的請求方法主要有如下 5 種,但實際上 getpost 就夠用了。

  1. get:獲取服務器上的一個資源
  2. post:在服務器上建立一個紫愛雲
  3. put:在服務器上更新資源(客戶端須要提交更新後的全部數據)
  4. patch:在服務器上更新資源(客戶端只須要提交所更新的數據)
  5. delete:在服務器上刪除一個資源

5.2 Flask-Restful 插件

  1. 安裝

    Flask-Restful 須要在 Flask 0.8 以上版本運行,在 python 2.6 以上版本運行,經過 pip install flask-restful 便可安裝。

  2. 使用

    使用以前必須從 flask_restful 中導入 ApiResource;而後用 Api 將初始化的 app 綁定起來;再定義一個類視圖,定義類視圖必須繼承自 Resource;最後用 add_resource 方法將接口(URL)與視圖綁定起來。完整代碼以下:

    from flask import Flask
     from flask_restful import Api,Resource  # Api 用來綁定 app,Resource 用來建立類視圖
    
     app = Flask(__name__)
     api = Api(app)
    
     class LoginView(Resource):
         def post(self):     # 定義了什麼樣的方法,才能用什麼樣的請求
             return {'username':'MYYD'}  # 能夠直接返回字典類型的數據(由於字典數據已經自動轉換成Json格式了)
    
     api.add_resource(LoginView,'/login/',endpoint='login')  # 映射類視圖和接口,endpoint 用來指定 url_for 反轉到類視圖時的關鍵字
    
     if __name__ == '__main__':
         app.run()
  3. 注意事項:

    1. 映射類視圖和接口時不指定 endpoint,則進行 url_for 反轉時默認使用視圖名稱的小寫,即上例中的 loginview
    1. add_resource 方法的第二個參數,用來指定訪問這個類視圖的接口,與以前不一樣的是,這個地方能夠傳入多個接口。

5.3 Flask-Restful 參數驗證

  1. 基本使用

    Flask-Restful 插件爲咱們提供了相似以前的 WTForm 表單驗證的包,能夠用來驗證提交的數據是否合法,叫作 reqparse。基本用法以下(3步驟):

    parser = reqparse.RequestParser()   # 初始化一個 RequestParser 對象
     parser.add_argument('password',type=int,help='password input error')    # 指定驗證的參數名稱,類型以及驗證不經過時的提示信息
     args = parser.parse_args()  # 執行驗證

    完整代碼以下:

    from flask_restful import Api,Resource,reqparse
    
     class LoginView(Resource):
         def post(self):     # post 方法提交數據時傳入的 username 和 password,這裏不須要定義
             parser = reqparse.RequestParser()
             parser.add_argument('username',type=str,help='用戶名格式錯誤') # 若是提交數據時沒傳入,默認爲 None
             parser.add_argument('age',type=int,help='密碼錯誤')
             args = parser.parse_args()
             print(args)
             return {'username':'MYYD'}
  2. add_argument 解析

    在使用 add_argument 對上傳的數據進行驗證時,能夠根據需求使用不一樣的選項進行驗證,經常使用的選項有:

    1. default:默認值,若是沒有傳入該參數,則使用 default 爲該參數指定默認的值。
    2. required:置爲 True 時(默認爲 False),該參數必須傳入值,不然拋出異常。
    3. type:指定該參數的類型,並進行強制轉換,若強制轉換失敗則拋出異常。
    4. choices:至關於枚舉類型,即該傳入的參數只能爲 choices 列表中指定的值。
    5. help:當驗證失敗時拋出的異常信息。
    6. trim:置爲 True 時對上傳的數據進行去空格處理(只去掉字符串先後的空格,不去掉字符串之間的空格)。

    其中,type 選項除了能夠指定 python 自帶的一些數據類型外,還能夠指定 flask_restful.inputs 下的一些特定類型來進行強制轉換。經常使用的類型以下:

    1. url:會判斷上傳的這個參數是否是一個 url,若不是則拋出異常。
    2. regex:會判斷上傳的這個參數是否符合正則表達式中的格式,若不符合則拋出異常。
    3. date:將上傳的這個參數強制轉換成 datetime.date 類型,若轉換不成功則拋出異常。

    在使用 type 指定 flask_restful.inputs 數據類型時的用法以下:

    parser.add_argument('birthday',type=inputs.date,help='日期輸入錯誤')

5.4 Flask-Restful 類視圖返回內容

返回數據時候可使用最原始的方法,返回一個字典。可是 Restful 推薦咱們使用 Restful 方法,以下:

  1. 先定義一個字典,該字典定義全部要返回的參數
  2. 再使用 marshal_with(字典名) 傳入字典名稱
  3. 最後返回數據就好了,以下:

    from flask_restful import Api,Resource,fields,marshal_with
     api = Api(app)
     class Article(object):
         def __init__(self,title,content):
             self.title = title
             self.content = content
     artilce = Article('MYYD','wuba luba dub dub')
     class LoginView(Resource):
         resource_field = {
             'title': fields.String,
             'content': fields.String
         }
         @marshal_with(resource_field)
         def get(self):
             return artilce      # 能夠直接返回 Article 的實例,會拿到 article 對象的兩個屬性並返回
     api.add_resource(LoginView,'/login/',endpoint='login')

這樣作的好處是:

  1. 能夠少寫代碼
  2. 能夠規範輸出,即若是 article 對象只有 title 屬性而沒有 content 屬性,也會返回 content 的值,只不過該值被置爲 None

5.5 Flask-Restful 標準返回

5.5.1 複雜結構

對於一個類視圖,能夠指定好一些數據字段用於返回。指定的這些數據字段,在此後使用 ORM 模型或者自定義模型時,會自動獲取模型中的相應字段,生成 Json 數據,並返回給客戶端。對於擁有子屬性的字段而言,若想成功獲取其屬性並返回給客戶端,須要引用 fields.Nested 並在其中定義子屬性的字段。整個例子以下:

  1. 模型關係

    class User(db.Model):
         __tablename__ = 'user'
         id = db.Column(db.Integer,primary_key=True)
         username = db.Column(db.String(50),nullable=False)
         email = db.Column(db.String(50),nullable=False)
    
     article_tag_table = db.Table(
         'article_tag',
         db.Column('article_id',db.Integer,db.ForeignKey("article.id"),primary_key=True),
         db.Column('tag_id',db.Integer,db.ForeignKey("tag.id"),primary_key=True)
     )
    
     class Article(db.Model):
         __tablename__ = 'article'
         id = db.Column(db.Integer,primary_key=True)
         title = db.Column(db.String(50),nullable=False)
         content = db.Column(db.Text)
         author_id = db.Column(db.Integer,db.ForeignKey('user.id'))
    
         author = db.relationship('User',backref='articles')
    
         tags = db.relationship('Tag',secondary=article_tag_table,backref='articles')
    
     class Tag(db.Model):
         __tablename__ = 'tag'
         id = db.Column(db.Integer,primary_key=True)
         name = db.Column(db.String(50),nullable=False)
  2. 返回時定義的數據字段

    注意這裏有三點必須實現:

    1. 導入相關包並初始化 app
    2. 定義返回數據的字段
    3. 使用裝飾器 marshal_with 傳入定義的數據字段
    from flask_restful import Api,Resource,fields,marshal_with
     api = Api(app)
     class ArticleView(Resource):
    
         article_detail = {
             'article_title': fields.String(attribute='title'),
             'content': fields.String,
             'author': fields.Nested({       # 返回有子屬性的字段時要用 fields.Nested() 
                 'username': fields.String,
                 'email': fields.String,
                 'age': fields.Integer(default=1)
             }),
             'tags': fields.Nested({         # 返回有子屬性的字段時要用 fields.Nested() 
                 'name': fields.String
             })
         }
         @marshal_with(article_detail)
         def get(self,article_id):
             article = Article.query.filter_by(id=article_id).first()
             return article
5.5.2 重命名屬性

重命名屬性很簡單,就是返回的時候使用不一樣於模型自己的字段名稱,此操做須要藉助 attribute 選項。以下所示代碼:

article_detail = {
    'article_title': fields.String(attribute='title')
}

Article 模型中的屬性本來是 title,可是要返回的字段想要命名爲 article_title。若是不使用 attribute 選項,則在返回時會去 Article 模型中找 article_title 屬性,很明顯是找不到的,這樣以來要返回的 article_title 字段會被置爲 Null。使用 attribute 選項後,當返回 article_title 字段時,會去 Article 模型中找 attribute 選項指定的 title 屬性,這樣就能夠成功返回了。

5.5.3 默認值

當要返回的字段沒有值時,會被置爲 Null,若是不想置爲 Null,則須要指定一個默認的值,此操做須要藉助 default 選項。以下代碼所示:

article_detail = {
    'article_title': fields.String(attribute='title')
    'readed_number': fields.Integer(default=0)
}

當想要返回一篇文章的閱讀量時,若沒有從模型中獲取到該字段的值,若不使用 default 選項則該字段會被置爲 Null;若使用了該選項,則該字段會被置爲 0

5.6 Flask-restful 細節

實際上,flask-restful 還能夠嵌套在藍圖中使用,也能返回一個 html 模板文件。

  1. 嵌套藍圖使用

    搭配藍圖使用時,在註冊 api 時就不須要使用 app 了,而是使用藍圖的名稱,以下:

    article_bp = Blueprint('article',__name__,url_prefix='/article')
     api = Api(article_bp)

    其餘的和以前同樣,不過要在主 app 文件中註冊一下藍圖。

  2. 渲染模板

    若是想使用 flask-restful 返回 html 模板,則必須使用 api.representation() 裝飾器來轉換返回數據的類型,並根據該裝飾器定義一個函數,用於返回該模板,以下:

    from flask import render_template,make_response
    
     @api.representation('text/html')
     def outPrintListForArticle(data,code,headers):  # 這裏要傳入這三個參數
         resp = make_response(data)  # 其中,data 就是模板的 html 代碼
         return resp
    
     class ListView(Resource):
         def get(self):
             return render_template('list.html')
     api.add_resource(ListView,'/list/',endpoint='list')
相關文章
相關標籤/搜索