<style>
html, body, .ui-content {
background-color: #333;
color: #ddd;
}
body > .ui-infobar {
display: none;
}
.ui-view-area > .ui-infobar {
display: block;
}
.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4,
.markdown-body h5,
.markdown-body h6 {
color: #ddd;
}
.markdown-body h1,
.markdown-body h2 {
border-bottom-color: #ffffff69;
}
.markdown-body h1 .octicon-link,
.markdown-body h2 .octicon-link,
.markdown-body h3 .octicon-link,
.markdown-body h4 .octicon-link,
.markdown-body h5 .octicon-link,
.markdown-body h6 .octicon-link {
color: #fff;
}
.markdown-body img {
background-color: transparent;
}
.ui-toc-dropdown .nav>.active:focus>a, .ui-toc-dropdown .nav>.active:hover>a, .ui-toc-dropdown .nav>.active>a {
color: white;
border-left: 2px solid white;
}
.expand-toggle:hover,
.expand-toggle:focus,
.back-to-top:hover,
.back-to-top:focus,
.go-to-bottom:hover,
.go-to-bottom:focus {
color: white;
}
.ui-toc-dropdown {
background-color: #333;
}
.ui-toc-label.btn {
background-color: #191919;
color: white;
}
.ui-toc-dropdown .nav>li>a:focus,
.ui-toc-dropdown .nav>li>a:hover {
color: white;
border-left: 1px solid white;
}
.markdown-body blockquote {
color: #bcbcbc;
}
.markdown-body table tr {
background-color: #5f5f5f;
}
.markdown-body table tr:nth-child(2n) {
background-color: #4f4f4f;
}
.markdown-body code,
.markdown-body tt {
color: #eee;
background-color: rgba(230, 230, 230, 0.36);
}
a,
.open-files-container li.selected a {
color: #5EB7E0;
}
</style>}
# Python + Flask 虛擬美國股票交易網站 Part3 (模板/ 模板上下文)
###### tags: `CS50` `Python` `Flask`
## 前言
網站首頁左側2/3為主體,顯示用戶個資,持股清單。右側1/3為邊欄,顯示用戶的觀察清單。因為不是每個頁面都會顯示觀察清單,因此將觀察清單放在局部模板__sidebar.html中。其餘的寫在基模板base.html中
### vfinance/templates/base.html 程式碼
```
{% from 'bootstrap/nav.html' import render_nav_item %}
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- documentation at http://getbootstrap.com/docs/4.1/, alternative themes at https://bootswatch.com/ -->
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet">
<!-- https://favicon.io/emoji-favicons/money-mouth-face/ -->
<link rel="icon" href="{{ url_for('static', filename = 'favicon.ico') }}">
<!-- css sheet -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}" type ='text/css'>
<title>C$50 Finance: {% block title %}{% endblock %}</title>
</head>
<body>
{% block nav %}
<nav class="navbar navbar-expand-md navbar-light bg-light border">
<div class="container">
<!-- navbar brand -->
<a class="navbar-brand" href="/"><span class="blue">C</span><span class="red">$</span><span class="yellow">5</span><span class="green">0</span> <span class="red">Finance</span></a>
<!-- Hambuger Button -->
<button aria-controls="navbar" aria-expanded="false" aria-label="Toggle navigation" class="navbar-toggler" data-target="#navbar" data-toggle="collapse" type="button">
<span class="navbar-toggler-icon"></span>
</button>
{% if current_user.is_authenticated %}
<div class="collapse navbar-collapse">
<ul class= 'nav navbar-nav mr-auto'>
<li class = 'nav-item dropdown'>
<a href="#" class='nav-link dropdown-toggle' data-toggle='dropdown' role = 'button' aria-haspopup='true' area-expanded='false'>
My Account <span class='caret'></span>
</a>
<div class='dropdown-menu' aria-labelledby='navbarDropdown'>
<a class='dropdown-item' href = "/">Portifolio</a>
<a class='dropdown-item' href = "{{ url_for('admin.trade_history')}}">History</a>
<a class='dropdown-item' href = "{{ url_for('admin.show_watchlist')}}">Watchlist</a>
</div>
</li>
<li class = 'nav-item dropdown'>
<a href="#" class='nav-link dropdown-toggle' data-toggle='dropdown' role = 'button' aria-haspopup='true' area-expanded='false'>
Trade <span class='caret'></span>
</a>
<div class='dropdown-menu' aria-labelledby='navbarDropdown'>
<a class='dropdown-item' href = "{{ url_for('admin.get_quote')}}">Buy</a>
<a class='dropdown-item' href = "#">Sell</a>
</div>
</li>
<li class = 'nav-item dropdown'>
<a href="#" class='nav-link dropdown-toggle' data-toggle='dropdown' role = 'button' aria-haspopup='true' area-expanded='false'>
BackTest <span class='caret'></span>
</a>
</li>
</ul>
</div>
<div class="navbar-collapse collapse ">
<ul class="navbar-nav ml-auto">
<form class="form-inline my-2 my-lg-0" method = 'post'
action="{{ url_for('admin.get_quote') }}">
{% if form %}
{{form.csrf_token}}
{% endif %}
<input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search" id ='symbol' name = 'symbol'>
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Quote</button>
</form>
<li class="nav-item">
<a class="nav-link" href="#">{{ current_user.username }}</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('auth.logout', next = request.full_path) }}">logout</a>
</li>
</ul>
</div>
{% else %}
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav navbar-right">
{{ render_nav_item('auth.register', "Register") }}
{{ render_nav_item('auth.login', "Login") }}
</ul>
</div>
{% endif %}
</div>
</nav>
{% endblock nav %}
<main class="container p-5">
{% for message in get_flashed_messages(with_categories=True) %}
<div class="alert alert-{{ message[0]}}" role='alert'>
<button type="button" class="close" data-dismiss="alert">×</button>
{{ message[1]}}
</div>
{% endfor %}
{% block content %}{% endblock %}
<footer class="small text-center text-muted">
Data provided for free by <a href="https://iextrading.com/developer">IEX</a>. View <a href="https://iextrading.com/api-exhibit-a/">IEX’s Terms of Use</a>.
</footer>
</main>
{% block scripts %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/jquery-3.2.1.slim.min.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/popper.min.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/bootstrap.min.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/script.js') }}"></script>
{{ moment.include_moment(local_js=url_for('static', filename='js/moment-with-locales.min.js')) }}
{% endblock scripts %}
</body>
</html>
```
## 註冊模板上下文 __init __.py
將template中會需要用到的模板註冊到工廠函數中
```
def register_template_context(app):
@app.context_processor
def make_template_context():
user = User.query.first()
if current_user.is_authenticated:
watchlist = Watchlist.query.with_parent(current_user).order_by(Watchlist.symbol.asc()).all()
priceInWatchlist = []
for stock in watchlist:
quote = lookup(stock.symbol)
price = quote['price']
priceInWatchlist.append(price)
return dict(
user = user,
watchlist = watchlist,
priceInWatchlist = priceInWatchlist
)
else:
return dict(user = user,)
```
## 願望清單模板 vfinance/templates/home/__sidebar.html
```
{% if watchlist %}
<div class='row'>
<div class="card mb-6">
<div class="card-header">Watchlist</div>
<ul class="list-group list-group-flush">
{% for n in range(watchlist|length) %}
<li class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">
<a href="{{ url_for('admin.show_quote', symbol = watchlist[n].symbol)}}">
{{ watchlist[n].symbol}}
</a>
<a>
{{ priceInWatchlist[n] }}
</a>
</li>
{% endfor %}
</ul>
</div>
</div>
{% endif %}
```