Try   HackMD

後端學習紀錄 Backend with Flask - Website with UI

tags: backend

Copyright 2021, 月下麒麟


Target

該筆記主要目標為使用Web之Python框架Flask
並結合資料庫框架Flask-SQLAlchemy與資料庫SQLite
另外,會著重在前端設計技法應用

Requirements

Flask == 2.0.1
Flask-SQLAlchemy == 2.5.1

Architecture

|---app
|    |---main.py
|    |---webflask.db
|    |---templates
|            |---base.html  << point
|            |---index.html
|            |---query.html << point
|            |---view.html  

Source Code

Python

from flask import flash from flask import Flask from flask import redirect from flask import render_template from flask import url_for from flask import request from flask_sqlalchemy import SQLAlchemy from datetime import datetime import os import sqlite3 # create an instance in the flask frame app = Flask(__name__) @app.route('/') def index(): return render_template("index.html") @app.route('/new') def news(): return render_template("new.html") @app.route('/query', methods=["POST","GET"]) def querys(): # connect with DB conn = sqlite3.connect(r'D:\10_database\imdb.db') cur = conn.cursor() # operate DB cur.execute('SELECT DISTINCT director FROM top_rated_movies ORDER BY director ASC') directors = cur.fetchall() # operate DB cur.execute('SELECT DISTINCT release_year FROM top_rated_movies ORDER BY release_year DESC') release_years = cur.fetchall() if request.method == 'POST': conn.close() return redirect(url_for('view.html')) conn.close() return render_template("query.html", director = directors, release_year = release_years) @app.route('/view', methods=["POST","GET"]) def views(): if request.method == 'POST': request.form.get('director') request.form.get('release_year') get_dirs = request.form.get('director') get_dir_strip = get_dirs.strip('(),\'\'') conn = sqlite3.connect(r'D:\10_database\imdb.db') cur = conn.cursor() # SELECT title FROM top_rated_movies WHERE director = 'Christopher Nolan' ORDER BY director ASC ; cur.execute("SELECT title FROM top_rated_movies WHERE director = (?) ORDER BY director ASC;", (get_dir_strip,)) #print(get_dirs.strip('(),\'\'')) res_movies = cur.fetchall() conn.close() get_years = request.form.get('release_year') get_year_strip = get_years.strip('(),\'\'') conn = sqlite3.connect(r'D:\10_database\imdb.db') cur = conn.cursor() # SELECT title, release_year FROM top_rated_movies WHERE release_year='1999' ORDER BY title ASC ; cur.execute("SELECT title, release_year FROM top_rated_movies WHERE release_year=(?) ORDER BY title ASC;", (get_year_strip,)) res_years = cur.fetchall() conn.close() return render_template("view.html", res_director = get_dirs, res_dir_movie = res_movies, res_year = get_years, res_dir_year = res_years ) return render_template("view.html") @app.route('/add', methods=["POST","GET"]) def adds(): return render_template("add.html") @app.route('/member') def members(): return render_template("member.html") if __name__ == "__main__": app.run()

HTML
base.html

<!DOCTYPE html> <html lang="zh-TW"> <head> <!-- <link rel="stylesheet" type="text/css" href="static/bar.css"> --> <title>{% block title %}{% endblock %}</title> <meta charset="utf-8"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"> </head> <body> <div id="title_bar" style="font-size: larger; background-color: goldenrod;"> Welcome to YueLin's movie </div> <div id="list_bar"> <nav class="navbar navbar-expand-sm bg-dark navbar-dark" style="background-color:coral ;"> <ul class="navbar-nav" > <li class="nav-item"> <a class="nav-link" href="/">首頁</a> </li> <li class="nav-item"> <a class="nav-link" href="/new">最新消息</a> </li> <li class="nav-item"> <a class="nav-link" href="/query">電影查詢</a> </li> <li class="nav-item"> <a class="nav-link" href="/add">電影新增</a> </li> <li class="nav-item"> <a class="nav-link" href="/member">會員登入</a> </li> <li class="nav-item"> <a class="nav-link" href="/view">查詢結果</a> </li> </ul> </nav> </div> <main> {% block main %}{% endblock %} </main> {% block script %}{% endblock %} </body> </html>

base.html作為所有頁面的母模板


index.html

{% extends "base.html" %} {% block title %}首頁{% endblock %} {% block main %} <div> <img src="https://storage.googleapis.com/afs-prod/media/ed5f8b8cba114c7b84e25e9420cafb6d/3000.jpeg" width="1400" height="500"> </div> {% endblock %}

套用base.html之後就可以在不同分頁有同樣底頁的效果


(參考網路圖片)


query.html

{% extends "base.html" %} {% block title %}查詢{% endblock %} {% block main %} <div> <form method="POST" action="{{ url_for('views') }}"> <div style="background-color: chocolate;"> <div> <label>請選擇導演名稱: (e.g. Christopher Nolan)</label> </div> <div> <select name="director"> {% for x in director %} <option value="{{ x }}">{{ x }}</option> {% endfor %} </select> </div> </div> <div style="background-color: darkcyan;"> <div> <label>請選擇電影年份: (e.g. 1991(含)之後的電影)</label> </div> <div> <select name="release_year"> {% for x in release_year %} <option value="{{ x }}">{{ x }}</option> {% endfor %} </select> </div> </div> <div> <input type="submit" value="提交"> </div> </form> </div> {% endblock %}


view.html

{% extends "base.html" %} {% block title %}視圖{% endblock %} {% block main %} <div style="background-color: chocolate;"> <div> 欲查詢的導演名稱: {{ res_director }} </div> <div> 該導演執導的電影: <br/> {% for x in res_dir_movie %} <li>{{ x }}</li> {% endfor %} </div> </div> <div style="background-color: darkcyan;"> <div> 欲查詢的電影年份: {{ res_year }} </div> <div> 該年份的電影: <br/> {% for x in res_dir_year %} <li>{{ x }}</li> {% endfor %} </div> </div> {% endblock %}


Discuss

.html
QA #1

<div> <select name="director"> {% for x in director %} <option value="{{ x }}">{{ x }}</option> {% endfor %} </select> </div>

網路上找到很炫的功能寫法(對大神來說應該在平常不過XD
可以把選單用templates的做法實作
對於將DB的資料轉變成選單內容,相當實用

QA #2
.py

#1 get_years = request.form.get('release_year') #2 get_year_strip = get_years.strip('(),\'\'') #3 conn = sqlite3.connect(r'D:\10_database\imdb.db') #4 cur = conn.cursor() # SELECT title, release_year FROM top_rated_movies WHERE release_year='1999' ORDER BY title ASC ; #5 cur.execute("SELECT title, release_year FROM top_rated_movies WHERE release_year=(?) ORDER BY title ASC;", (get_year_strip,)) #6 res_years = cur.fetchall() #7 conn.close()

此為Python Code,
#1為取的在query頁面的option資訊選項
#2因為取得的資料格式不符合SQL語法的string搜尋條件,在此進行處理
#3連線到DB
#4連線指標
#5利用問號,將取得的變數填入,執行SQL語句
#6取得搜尋資料
#7結束連線


Summary

這次的練習仍是將前後端放在一起,
但著重在HTML結合TemplateJinja2的應用,
搭配base.html讓後續新增加的頁面模板,可以快速套用底板

因這個為較早時間的自我練習,故截圖沿用他處較模糊,
另外,就不再多著墨程式細節解釋,
如有問題,歡迎留言給我喔~