從零開始用 Flask 搭建一個網站(三)


從零開始用 Flask 搭建一個網站(二) 介紹了有關於數據庫的運用,接下來我們在完善一下數據在前端以及前端到后端之間的交互。本節涉及到前端,因此也會講解一下 jinja2 模板、jQuery、ajax 等用法。

下面我們來創建兩個界面,一個可以新建 channel,並顯示,另一個可以創建 integration,並且可以綁定一個之前創建的 channel。

post2channel.html

{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}

{% block head %}    
{{ super() }}    
<link rel="stylesheet" href="{{ url_for('static', filename='css/post2channel.css') }}">    
<link rel="stylesheet" href="{{ url_for('static', filename='css/toastr.css') }}">    
<script type="text/javascript" src="{{ url_for('static', filename= 'js/jquery.min.js') }}"></script>    
<script type="text/javascript" src="{{ url_for('static', filename='js/toastr.js') }}"></script>    
<script type="text/javascript" src="{{ url_for ('static', filename='js/')}}"></script>
{% endblock %}

{% block title %}極光寶盒-創建集成{% endblock %}
{% block navbar %}    
<div id="navigationbar"></div>    
{{ super() }}
{% endblock %}

...

我們從第一行開始來講解一下這個模板,第一句

{% extends "base.html" %}

從字面上可以明白這個模板繼承了 base.html 模板,使用 {% %} 是 jinja2 模板的語法,表示語句塊,還有一種分隔符 {{ }} ,表示變量,通常用來在模板上顯示。接下來是

{% block head %}

可以看到也是比較容易理解的語法,block 后接一個 block name,表示一個塊開始的聲明,結束的時候用 {% end %} 即可。在塊中可以使用普通的 HTML 語法。{{ super() }} 表示繼承父模板的塊聲明,這里指繼承 base.html 中聲明的 head 塊。接下來是 css 和 js 文件的引用。此頁面使用了 toastr 來顯示通知,類似於 Android 中的 Toast,有興趣的可以了解一下它的詳細用法。

接下來是HTML代碼,有一個下拉輸入框和按鈕。

<ul id="content" class="dropdown-menu dropdown-menu-right">    
  {% for channel in channels %}        
    <li id="{{ channel }}" class="channel_class"><a>{{ channel }}</a></li>    
  {% endfor %}
</ul>

以上代碼就是下拉輸入框中的數據來源,用了一個for循環來遍歷 channels 列表,並且用 li 包裹每個元素,這也是模板常見的用法。channels 是在視圖函數中傳過來的。

auth/views.py

@auth.route('/new/post_to_channel', methods=['GET'])
def post_to_channel():    
  developer = get_developer()    
  dev_key = developer.dev_key    
  channels = get_channel_list()    
  return render_template('auth/new/post2channel.html', **locals())

remder_template 的第二個參數表明,渲染這個 post2channel.html 頁面的時候,把以上所有的變量都傳遞到頁面中,這樣就可以使用 {{ }} 模板語法拿到。接下來回到 post2channel.html, 看到部分:

$('#create_integration_btn').click(function () {    
  var channel = $('#selected_channel').val();   
  console.log('create integration, channel: ' + channel);    
  if (channel != '') {        
    $.ajax({            
    type: "POST",            
    contentType: "application/json; charset=utf-8",            
    url: "../../v1/developers/{{ dev_key }}/integrations",            
    data: JSON.stringify({channel: channel}),            
    success: function (data) {                
      if (data != undefined) {                    
        if (data["token"]) {                       
          window.location.href = '/auth/manage/create_integration/' + data["integration_id"] + '/' + data["token"] + '/' + channel                    
        }                
      } else {                    
        toastr.error("服務器異常");                
      }            
    },            
      error: function (error) {                
        console.log(error);                
        toastr.error("創建失敗");            
      },            
      dataType: "json"        
    })    
  }
})

這是創建集成按鈕的邏輯,用 jQuery 的 ajax 發送 post 請求,以 json 格式將輸入框中的 channel 值傳到 url 表明的視圖函數。這里的 url 是相對路徑。在 ajax 中有 success 和 error 兩個函數,分別是請求成功和失敗的回調函數。下面看到這個請求的視圖函數,我們來看看視圖函數是如何處理從頁面傳過來的數據。

api_1_0/developers.py

# 添加一個集成,並返回 integration_id ,如果 channel 已存在,直接綁定該 channel, 否則新建一個 channel@api.route('/developers/<dev_key>/integrations', methods=['POST'])
def create_integrations(dev_key):
# 先判斷一下傳過來的 json 數據是否符合要求
  if not request.json or not 'channel' in request.json:    
    print("request json error")    
    abort(400)
#從數據庫得到 developer
  developer = Developer.query.filter_by(dev_key=dev_key).first()
  if developer is None:    
    print("developer not found")    
    abort(400)
  #以下省略
  ...
  #最后返回相關數據
  return jsonify({'integration_id': new_integration_id,                
                  'token': token.decode('utf-8')}), 201

以上代碼創建成功后也返回了一個 json,這樣在 success 的回調函數中就能得到這個數據,用於在跳轉到其他界面的時候做一些初始化操作。即以下代碼:

if (data != undefined) { 
  if (data["token"]) { 
    window.location.href = '/auth/manage/create_integration/' + data["integration_id"] + '/' + data["token"] + '/' + channel 
  } 
}

這里將參數放到 url 中,調用了對應的視圖函數:

auth/views.py

@auth.route('/manage/create_integration/<string:integration_id>/<string:token>/<string:channel>', methods=['GET', 'POST'])
def create_integration(integration_id, token, channel):    
  integration = Integration.query.filter_by(integration_id=integration_id).first()    
  channels = get_channel_list()    
  developer = get_developer()    
  dev_key = developer.dev_key    
  return render_template('auth/create.html', **locals())

可以看到上面的參數就是從 post2channel 頁面傳過來的,並且還從數據庫中查詢到對應的 integration,然后將相關數據傳到 create.html,讓后者渲染頁面。

我們通過一個例子看到數據在前端和后端、前端之間的交互。總結一下,無非就是在前端頁面中發送請求,然后在視圖函數中操作數據庫,並且返回相關數據,回調到前端頁面中,最后在回調中調用另一個視圖函數,在跳轉頁面時利用得到的數據渲染頁面。一切就是這么簡單,沒什么黑魔法!源碼在 github 上。下一節介紹一下 flask_oauthlib 的用法,學習一下如何使用 oath2 第三方授權登錄以及調用提供方的相關 API。


作者:KenChoi - 極光
原文:從零開始用 Flask 搭建一個網站(三)
知乎專欄:極光日報


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM