learning from 100 Days of Code: The Complete Python Pro Bootcamp for 2022
Learning Point
Jinja - include 所有網站共用header / footer / navigation
{% include 'header.html' %}
{% include 'navigation.html' %}
<!-- 連結css -->
<link href="{{ url_for('static', filename='css/styles.css') }}" rel="stylesheet" />
<!-- 連結js -->
<script src="{{ url_for('static', filename='js/scripts.js') }}"></script>
<!-- 連結img -->
<header class="masthead" style="background-image: url('{{ url_for('static', filename='assets/img/about-bg.jpg') }}')">
- POST request
# index.html - form
<form action="{{ url_for('go_login') }}" method="post">
<label>Name</label>
<input type="text" placeholder="name" name="name">
<label>Password</label>
<input type="password" placeholder="password" name="password">
<button type="submit">OK</button>
</form>
# main.py - POST & GET
@app.route('/login', methods=['POST', 'GET'])
def go_login():
error = None
if request.method == 'POST':
try:
name = request.form['name']
password = request.form['password']
return f"<h1>Name: {name}, Password: {password}</h1>"
except KeyError:
error = 'Invalid username/password'
return f"<h1>It's NOT POST request<h1>" \
f"<p>Error: {error}</p>"
main.py
from flask import Flask, render_template, request
import requests
import smtplib
import os
app = Flask(__name__)
post_url = "https://api.npoint.io/46e5db86a271b1e8bd5c"
post_response = requests.get(post_url)
posts = post_response.json()
MY_EMAIL = os.environ['MY_EMAIL']
PASSWORD = os.environ['PASSWORD']
@app.route("/")
def home_page():
return render_template("index.html", posts=posts)
@app.route("/post/<index>")
def go_post(index):
index = int(index)
return render_template("post.html", post=posts[index])
@app.route("/about")
def go_about():
return render_template("about.html")
@app.route("/contact", methods=['GET'])
def go_contact():
return render_template("contact.html", method='get')
@app.route("/contact", methods=['POST'])
def receive_data():
name = request.form['name']
email = request.form['email']
phone = request.form['phone']
msg = request.form['msg']
with smtplib.SMTP("smtp.gmail.com", 587, timeout=120) as smtp:
smtp.starttls()
smtp.login(user=MY_EMAIL, password=PASSWORD)
smtp.sendmail(from_addr=MY_EMAIL,
to_addrs=MY_EMAIL,
msg=f"Subject:From Clean Blog\n\n"
f"name: {name}\nphone: {phone}\n"
f"email: {email}\nmsg: {msg}".encode('utf-8'))
return render_template("contact.html", method='post')
if __name__ == "__main__":
app.run(debug=True)
index.html
<!DOCTYPE html>
<html lang="en">
{% include 'header.html' %}
<body>
<!-- Navigation-->
{% include 'navigation.html' %}
<!-- Page Header-->
<header class="masthead" style="background-image: url('{{ url_for('static', filename='assets/img/home-bg.jpg')}}')">
<div class="container position-relative px-4 px-lg-5">
<div class="row gx-4 gx-lg-5 justify-content-center">
<div class="col-md-10 col-lg-8 col-xl-7">
<div class="site-heading">
<h1>Clean Blog</h1>
<span class="subheading">A Blog Theme by Start Bootstrap</span>
</div>
</div>
</div>
</div>
</header>
<!-- Main Content-->
<div class="container px-4 px-lg-5">
<div class="row gx-4 gx-lg-5 justify-content-center">
<div class="col-md-10 col-lg-8 col-xl-7">
{% for post in posts %}
<!-- Post preview-->
<div class="post-preview">
<a href="{{ url_for('go_post', index=post.id - 1) }}">
<h2 class="post-title">{{ post.title }}</h2>
<h3 class="post-subtitle">{{ post.subtitle }}</h3>
</a>
<p class="post-meta">
Posted by
<a href="{{ url_for('home_page') }}">{{ post.author }}</a>
on {{ post.date }}
</p>
</div>
<!-- Divider-->
<hr class="my-4" />
{% endfor %}
<!-- Pager-->
<div class="d-flex justify-content-end mb-4"><a class="btn btn-primary text-uppercase" href="#!">Older Posts →</a></div>
</div>
</div>
</div>
<!-- Footer-->
{% include 'footer.html' %}
</body>
</html>
post.html
<!DOCTYPE html>
<html lang="en">
{% include 'header.html' %}
<body>
<!-- Navigation-->
{% include 'navigation.html' %}
<!-- Page Header-->
<header class="masthead" style="background-image: url('{{ url_for('static', filename='assets/img/post-bg.jpg') }}')">
<div class="container position-relative px-4 px-lg-5">
<div class="row gx-4 gx-lg-5 justify-content-center">
<div class="col-md-10 col-lg-8 col-xl-7">
<div class="post-heading">
<h1>{{ post.title }}</h1>
<h2 class="subheading">{{ post.subtitle }}</h2>
<span class="meta">
Posted by
<a href="#!">{{ post.author }}</a>
on {{ post.date }}
</span>
</div>
</div>
</div>
</div>
</header>
<!-- Post Content-->
<article class="mb-4">
<div class="container px-4 px-lg-5">
<div class="row gx-4 gx-lg-5 justify-content-center">
<div class="col-md-10 col-lg-8 col-xl-7">
<p>{{ post.body }}</p>
</div>
</div>
</div>
</article>
<!-- Footer-->
{% include 'footer.html' %}
</body>
</html>
header.html
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="description" content="" />
<meta name="author" content="" />
<title>Clean Blog - Start Bootstrap Theme</title>
<link rel="icon" type="image/x-icon" href="assets/favicon.ico" />
<!-- Font Awesome icons (free version)-->
<script src="https://use.fontawesome.com/releases/v6.1.0/js/all.js" crossorigin="anonymous"></script>
<!-- Google fonts-->
<link href="https://fonts.googleapis.com/css?family=Lora:400,700,400italic,700italic" rel="stylesheet" type="text/css" />
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800" rel="stylesheet" type="text/css" />
<!-- Core theme CSS (includes Bootstrap)-->
<link href="{{ url_for('static', filename='css/styles.css') }}" rel="stylesheet" />
</head>
navigation.html
<nav class="navbar navbar-expand-lg navbar-light" id="mainNav">
<div class="container px-4 px-lg-5">
<a class="navbar-brand" href="index.html">Start Bootstrap</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
Menu
<i class="fas fa-bars"></i>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ms-auto py-4 py-lg-0">
<li class="nav-item"><a class="nav-link px-lg-3 py-3 py-lg-4" href="{{ url_for('home_page') }}">Home</a></li>
<li class="nav-item"><a class="nav-link px-lg-3 py-3 py-lg-4" href="{{ url_for('go_about') }}">About</a></li>
<li class="nav-item"><a class="nav-link px-lg-3 py-3 py-lg-4" href="{{ url_for('go_contact') }}">Contact</a></li>
</ul>
</div>
</div>
</nav>
footer.html
<footer class="border-top">
<div class="container px-4 px-lg-5">
<div class="row gx-4 gx-lg-5 justify-content-center">
<div class="col-md-10 col-lg-8 col-xl-7">
<ul class="list-inline text-center">
<li class="list-inline-item">
<a href="#!">
<span class="fa-stack fa-lg">
<i class="fas fa-circle fa-stack-2x"></i>
<i class="fab fa-twitter fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
<li class="list-inline-item">
<a href="#!">
<span class="fa-stack fa-lg">
<i class="fas fa-circle fa-stack-2x"></i>
<i class="fab fa-facebook-f fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
<li class="list-inline-item">
<a href="#!">
<span class="fa-stack fa-lg">
<i class="fas fa-circle fa-stack-2x"></i>
<i class="fab fa-github fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
</ul>
<div class="small text-center text-muted fst-italic">Copyright © Your Website 2022</div>
</div>
</div>
</div>
</footer>
<!-- Bootstrap core JS-->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<!-- Core theme JS-->
<script src="{{ url_for('static', filename='js/scripts.js') }}"></script>