iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 7
1
自我挑戰組

DevOps學習之旅系列 第 7

Day 7 Mock 系統頁面開發

簡介

上一篇介紹 API 測試程式,還缺少頁面程式,和測試程式,基本上這邊會等前端把頁面寫好,才會交由後端來串接,這個專案是一個簡單的專案,實作最基本的頁面程式,並寫頁面測試程式,現在網站設計都不會使用重新載入整頁,因為這樣很浪費流量,都使用 ajax 的方式向後端 API 更新資料,拿到資料後才會更新網頁,這樣就不會浪費流量了.

串接頁面其實會需要用到html、css、javascript、jquery 等前端技術,html和css只要會基本就好,比較著重javascript和jqery的使用,有時候會和前端工程師配合調整頁面,使整體使用體驗更好.

Template

layout.jinja2 : html樣板

<!DOCTYPE html>
<html lang="{{request.locale_name}}">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="pyramid web application">
    <meta name="author" content="Pylons Project">
    <link rel="shortcut icon" href="{{request.static_url('ithome_pellok_2018:static/pyramid-16x16.png')}}">

    <title>Alchemy Scaffold for The Pyramid Web Framework</title>

    <!-- Bootstrap core CSS -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

    <!-- Optional theme -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">

    <!-- Custom styles for this scaffold -->
    <link href="{{request.static_url('ithome_pellok_2018:static/theme.css')}}" rel="stylesheet">
  </head>

  <body>
    {% block content %}
        <p>No content</p>
    {% endblock content %}
    
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="https://code.jquery.com/jquery-3.3.1.min.js"
    integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
    crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
    {% block javascript %}
    {% endblock javascript %}
  </body>
</html>

home.jinja2 : 首頁 html 程式

{% extends "layout.jinja2" %}

{% block content %}
<div class="content">
  <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
    <h1>Hello World Mock Server</h1>
  </div>
  <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
    <form class="form-inline">
    
      <div class="form-group" style="display:inline-flex;">
        <label style="margin:5px 10px; ">name:</label>
        <input type="text" class="form-control" name="name" id="add_name" placeholder="name">
        <label style="margin:5px 10px;">value:</label>
        <input type="text" class="form-control" name="value" id="add_value" placeholder="value">
      </div>
      <button type="submit" class="btn btn-primary add_btn">Add</button>
    </form>
  </div>

  <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
    <table class="table table-hover">
      <thead>
        <tr>
          <th>name</th>
          <th>value</th>
        </tr>
      </thead>
      <tbody class="api_table">

      </tbody>
    </table>
  </div>
  
</div>
{% endblock content %}

{% block javascript %}
<script>
  // read data
    $(document).ready(function(){
        search();
    });
    $(document).on('click', '.add_btn', function() {
        var form_data = new FormData();
        form_data.append('name', $('#add_name').val());
        form_data.append('value', $('#add_value').val());
        create(form_data);
    });
    function search(){
        $.ajax({
            url: "{{ request.route_url('api')}}",
            type: 'GET',
                contentType: false,
                processData: false,

            beforeSend: function () {
            },
            error: function (xhr) {
                alert('Ajax request 發生錯誤');
             },
            success: function (response) {
                if (response['status']) {
                    {#alert("搜尋成功");#}
                    $('.api_table tr').remove();
                    var html = "";
                    response['response'].forEach(function (value, index) {
                        html +="<tr><td>"+value['name']+"</td><td>"+value['value']+"</td></tr>"
                    });
                    $('.api_table').append(html);
                    console.log(response);

                } else {
                }
            },
            complete: function () {
            }
        });
    }
    function create(form_data) {
        $.ajax({
            url: "{{ request.route_url('api')}}",
            type: 'POST',
                data: form_data,
                contentType: false,
                processData: false,

            beforeSend: function () {
                $('.add_btn').attr('disabled', true);
            },
            error: function (xhr) {
                alert('Ajax request 發生錯誤');
             },
            success: function (response) {
                if (response['status']) {
                    {#alert("創建成功");#}
                    console.log(response);
                    $('.add_btn').attr('disabled', false);
                } else {
                  $('.add_btn').attr('disabled', false);
                }
            },
            complete: function () {
              $('.add_btn').attr('disabled', false);
              search()
            }
        });
    }
</script>
{% endblock javascript %}

page/init.py : 定義頁面路由

from . import page

def includeme(config):
    config.add_route('page.home', '/')
    config.add_view(
        page.PageView, attr='home',
        route_name='page.home',
        renderer='../../templates/home.jinja2'
    )

page.py : 定義頁面主邏輯

# coding=utf8
from __future__ import unicode_literals
from pyramid.response import Response

class PageView(object):
    def __init__(self, request):
        super(PageView, self).__init__()
        self.request = request

    def home(self):
        """
        首頁
        """
        try:
            return {}
        except Exception as e:
            return Response(str(e), content_type='text/plain', status=500)

Function 測試

test_function.py : 頁面測試

import transaction
import unittest
import webtest
from ithome_pellok_2018.models.meta import Base
from ithome_pellok_2018.models import get_tm_session
from ithome_pellok_2018 import main

class FunctionalTests(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        settings = {
            'sqlalchemy.url': 'sqlite://',
            'auth.secret': 'seekrit',
        }
        app = main({}, **settings)
        cls.testapp = webtest.TestApp(app)

        session_factory = app.registry['dbsession_factory']
        cls.engine = session_factory.kw['bind']
        Base.metadata.create_all(bind=cls.engine)

        with transaction.manager:
            dbsession = get_tm_session(session_factory, transaction.manager)

    @classmethod
    def tearDownClass(cls):
        Base.metadata.drop_all(bind=cls.engine)

    def test_home(self):
        res = self.testapp.get('/', status=200)
        self.assertTrue(b'Hello World Mock Server' in res.body)

結論

在串接頁面的時候會先把公用性高的主樣式程式(header、footer、sildebar)抽出來,寫在loayout.jinja2,每頁面都會使用套用這個樣式,只要更動頁面內容就好,向 home.jinja2 的內容只是首頁內容資料,這邊只實作到基礎創建和搜尋功能.

參考

bitbucket Repostory
Template Jinja2


上一篇
Day 6 Mock 系統測試程式
下一篇
Day 8 專案部署
系列文
DevOps學習之旅30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言