On this page
วันที่ 26 — เว็บด้วย Python (Python Web)
เรียนใช้ Flask สร้างเว็บแอปพลิเคชันด้วย Python — ตั้งแต่ route แรก จนถึง deploy บน Heroku

Python สำหรับเว็บ
Python เป็นภาษาโปรแกรมที่ใช้งานทั่วไปและสามารถนำไปใช้ได้หลายที่ ในส่วนนี้ เราจะดูว่าเราใช้ Python สำหรับเว็บได้อย่างไร มี Python web framework มากมาย Django และ Flask เป็น framework ที่ได้รับความนิยมมากที่สุด วันนี้ เราจะดูวิธีใช้ Flask สำหรับ web development
Flask
Flask เป็น web development framework ที่เขียนด้วย Python Flask ใช้ Jinja2 template engine Flask ยังสามารถใช้ร่วมกับ front-end library สมัยใหม่อื่น ๆ เช่น React ได้
ถ้าคุณยังไม่ได้ติดตั้ง package virtualenv ให้ติดตั้งก่อน Virtual environment จะช่วยแยก project dependencies ออกจาก dependencies บนเครื่อง local
โครงสร้างโฟลเดอร์
หลังจากทำครบทุกขั้นตอนแล้ว โครงสร้างไฟล์ของ project ควรมีหน้าตาแบบนี้:
├── Procfile
├── app.py
├── env
│ ├── bin
├── requirements.txt
├── static
│ └── css
│ └── main.css
└── templates
├── about.html
├── home.html
├── layout.html
├── post.html
└── result.htmlการตั้งค่า Project Directory
ทำตามขั้นตอนต่อไปนี้เพื่อเริ่มต้นใช้ Flask
ขั้นตอนที่ 1: ติดตั้ง virtualenv โดยใช้คำสั่งต่อไปนี้
pip install virtualenvขั้นตอนที่ 2:
asabeneh@Asabeneh:~/Desktop$ mkdir python_for_web
asabeneh@Asabeneh:~/Desktop$ cd python_for_web/
asabeneh@Asabeneh:~/Desktop/python_for_web$ virtualenv venv
asabeneh@Asabeneh:~/Desktop/python_for_web$ source venv/bin/activate
(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ pip freeze
(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ pip install Flask
(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ pip freeze
Click==7.0
Flask==1.1.1
itsdangerous==1.1.0
Jinja2==2.10.3
MarkupSafe==1.1.1
Werkzeug==0.16.0
(env) asabeneh@Asabeneh:~/Desktop/python_for_web$เราสร้าง project directory ชื่อ python_for_web ภายใน project เราสร้าง virtual environment ชื่อ venv (จะตั้งชื่ออะไรก็ได้แต่ผู้เขียนชอบใช้ชื่อ venv) จากนั้น activate virtual environment เราใช้ pip freeze เพื่อตรวจสอบ package ที่ติดตั้งใน project directory ผล pip freeze ว่างเปล่าเพราะยังไม่ได้ติดตั้ง package
ตอนนี้ มาสร้างไฟล์ app.py ใน project directory และเขียนโค้ดต่อไปนี้ ไฟล์ app.py จะเป็นไฟล์หลักของ project โค้ดต่อไปนี้มี flask module และ os module
การสร้าง Routes
Home route
# let's import the flask
from flask import Flask
import os # importing operating system module
app = Flask(__name__)
@app.route('/') # this decorator create the home route
def home ():
return '<h1>Welcome</h1>'
if __name__ == '__main__':
# for deployment we use the environ
# to make it work for both production and development
port = int(os.environ.get("PORT", 5000))
app.run(debug=True, host='0.0.0.0', port=port)ในการรัน flask application ให้พิมพ์ python app.py ใน directory หลักของ flask application
หลังจากรัน python app.py แล้วให้เช็ค local host 5000
มาเพิ่ม route เพิ่มเติม โดยสร้าง about route
# let's import the flask
from flask import Flask
import os # importing operating system module
app = Flask(__name__)
@app.route('/') # this decorator create the home route
def home ():
return '<h1>Welcome</h1>'
@app.route('/about')
def about():
return '<h1>About us</h1>'
if __name__ == '__main__':
# for deployment we use the environ
# to make it work for both production and development
port = int(os.environ.get("PORT", 5000))
app.run(debug=True, host='0.0.0.0', port=port)ตอนนี้ เราได้เพิ่ม about route แล้ว แล้วถ้าเราต้องการ render ไฟล์ HTML แทนที่จะเป็น string ล่ะ? สามารถ render ไฟล์ HTML ได้โดยใช้ function render_template มาสร้างโฟลเดอร์ชื่อ templates และสร้าง home.html และ about.html ใน project directory มา import function render_template จาก flask ด้วย
การสร้าง Templates
สร้างไฟล์ HTML ภายในโฟลเดอร์ templates
home.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Home</title>
</head>
<body>
<h1>Welcome Home</h1>
</body>
</html>about.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>About</title>
</head>
<body>
<h1>About Us</h1>
</body>
</html>Python Script
app.py
# let's import the flask
from flask import Flask, render_template
import os # importing operating system module
app = Flask(__name__)
@app.route('/') # this decorator create the home route
def home ():
return render_template('home.html')
@app.route('/about')
def about():
return render_template('about.html')
if __name__ == '__main__':
# for deployment we use the environ
# to make it work for both production and development
port = int(os.environ.get("PORT", 5000))
app.run(debug=True, host='0.0.0.0', port=port)ดังที่เห็น การไปยังหน้าต่าง ๆ หรือการ navigate จำเป็นต้องมี navigation มาเพิ่ม link ไปยังแต่ละหน้า หรือสร้าง layout ที่ใช้ในทุกหน้า
Navigation
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>ตอนนี้ เราสามารถ navigate ระหว่างหน้าต่าง ๆ โดยใช้ link ด้านบน มาสร้างหน้าเพิ่มเติมที่จัดการข้อมูลฟอร์ม ตั้งชื่อได้ตามต้องการ ผู้เขียนชอบเรียกว่า post.html
เราสามารถ inject ข้อมูลลงในไฟล์ HTML โดยใช้ Jinja2 template engine
# let's import the flask
from flask import Flask, render_template, request, redirect, url_for
import os # importing operating system module
app = Flask(__name__)
@app.route('/') # this decorator create the home route
def home ():
techs = ['HTML', 'CSS', 'Flask', 'Python']
name = '30 Days Of Python Programming'
return render_template('home.html', techs=techs, name = name, title = 'Home')
@app.route('/about')
def about():
name = '30 Days Of Python Programming'
return render_template('about.html', name = name, title = 'About Us')
@app.route('/post')
def post():
name = 'Text Analyzer'
return render_template('post.html', name = name, title = name)
if __name__ == '__main__':
# for deployment
# to make it work for both production and development
port = int(os.environ.get("PORT", 5000))
app.run(debug=True, host='0.0.0.0', port=port)มาดู templates ด้วย:
home.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Home</title>
</head>
<body>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
<h1>Welcome to {{name}}</h1>
<ul>
{% for tech in techs %}
<li>{{tech}}</li>
{% endfor %}
</ul>
</body>
</html>about.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>About Us</title>
</head>
<body>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
<h1>About Us</h1>
<h2>{{name}}</h2>
</body>
</html>การสร้าง Layout
ในไฟล์ template มีโค้ดที่ซ้ำกันมาก เราสามารถเขียน layout และลบความซ้ำซ้อนออกได้ มาสร้าง layout.html ภายในโฟลเดอร์ templates หลังจากสร้าง layout แล้ว เราจะ import ไปใช้ในทุกไฟล์
การ Serve ไฟล์ Static
สร้างโฟลเดอร์ static ใน project directory ภายในโฟลเดอร์ static สร้างโฟลเดอร์ CSS หรือ styles แล้วสร้าง CSS stylesheet เราใช้ module url_for เพื่อ serve ไฟล์ static
layout.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
href="https://fonts.googleapis.com/css?family=Lato:300,400|Nunito:300,400|Raleway:300,400,500&display=swap"
rel="stylesheet"
/>
<link
rel="stylesheet"
href="{{ url_for('static', filename='css/main.css') }}"
/>
{% if title %}
<title>30 Days of Python - {{ title}}</title>
{% else %}
<title>30 Days of Python</title>
{% endif %}
</head>
<body>
<header>
<div class="menu-container">
<div>
<a class="brand-name nav-link" href="/">30DaysOfPython</a>
</div>
<ul class="nav-lists">
<li class="nav-list">
<a class="nav-link active" href="{{ url_for('home') }}">Home</a>
</li>
<li class="nav-list">
<a class="nav-link active" href="{{ url_for('about') }}">About</a>
</li>
<li class="nav-list">
<a class="nav-link active" href="{{ url_for('post') }}"
>Text Analyzer</a
>
</li>
</ul>
</div>
</header>
<main>
{% block content %} {% endblock %}
</main>
</body>
</html>ตอนนี้ มาลบโค้ดที่ซ้ำซ้อนในไฟล์ template อื่น ๆ แล้ว import layout.html href ใช้ function url_for พร้อมชื่อ route function เพื่อเชื่อมต่อแต่ละ navigation route
home.html
{% extends 'layout.html' %} {% block content %}
<div class="container">
<h1>Welcome to {{name}}</h1>
<p>
This application clean texts and analyse the number of word, characters and
most frequent words in the text. Check it out by click text analyzer at the
menu. You need the following technologies to build this web application:
</p>
<ul class="tech-lists">
{% for tech in techs %}
<li class="tech">{{tech}}</li>
{% endfor %}
</ul>
</div>
{% endblock %}about.html
{% extends 'layout.html' %} {% block content %}
<div class="container">
<h1>About {{name}}</h1>
<p>
This is a 30 days of python programming challenge. If you have been coding
this far, you are awesome. Congratulations for the job well done!
</p>
</div>
{% endblock %}post.html
{% extends 'layout.html' %} {% block content %}
<div class="container">
<h1>Text Analyzer</h1>
<form action="https://thirtydaysofpython-v1.herokuapp.com/post" method="POST">
<div>
<textarea rows="25" name="content" autofocus></textarea>
</div>
<div>
<input type="submit" class="btn" value="Process Text" />
</div>
</form>
</div>
{% endblock %}Request methods มี request method หลายแบบ (GET, POST, PUT, DELETE) ซึ่งเป็น request method ทั่วไปที่ช่วยให้เราทำ CRUD (Create, Read, Update, Delete) operation ได้
ใน post route เราจะใช้ method GET และ POST สลับกันขึ้นอยู่กับประเภทของ request ดูได้ในโค้ดด้านล่าง request method เป็น function สำหรับจัดการ request methods และยังใช้เข้าถึงข้อมูล form ได้ด้วย
app.py
# let's import the flask
from flask import Flask, render_template, request, redirect, url_for
import os # importing operating system module
app = Flask(__name__)
# to stop caching static file
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 0
@app.route('/') # this decorator create the home route
def home ():
techs = ['HTML', 'CSS', 'Flask', 'Python']
name = '30 Days Of Python Programming'
return render_template('home.html', techs=techs, name = name, title = 'Home')
@app.route('/about')
def about():
name = '30 Days Of Python Programming'
return render_template('about.html', name = name, title = 'About Us')
@app.route('/result')
def result():
return render_template('result.html')
@app.route('/post', methods= ['GET','POST'])
def post():
name = 'Text Analyzer'
if request.method == 'GET':
return render_template('post.html', name = name, title = name)
if request.method =='POST':
content = request.form['content']
print(content)
return redirect(url_for('result'))
if __name__ == '__main__':
# for deployment
# to make it work for both production and development
port = int(os.environ.get("PORT", 5000))
app.run(debug=True, host='0.0.0.0', port=port)จนถึงตอนนี้ เราได้เรียนวิธีใช้ template วิธี inject ข้อมูลลงใน template วิธีสร้าง common layout แล้ว ตอนนี้ มาจัดการไฟล์ static กัน สร้างโฟลเดอร์ชื่อ static ใน project directory แล้วสร้างโฟลเดอร์ชื่อ css ภายใน css สร้าง main.css ไฟล์ main.css ของคุณจะถูก link ใน layout.html
ไม่จำเป็นต้องเขียนไฟล์ css เอง ให้ copy แล้วนำไปใช้ได้เลย มาต่อกันที่การ deploy
การ Deploy
การสร้างบัญชี Heroku
Heroku ให้บริการ deployment ฟรีสำหรับทั้ง front end และ fullstack applications สร้างบัญชีที่ heroku แล้วติดตั้ง heroku CLI สำหรับเครื่องของคุณ หลังจากติดตั้ง heroku แล้ว พิมพ์คำสั่งต่อไปนี้
การ Login เข้า Heroku
asabeneh@Asabeneh:~$ heroku login
heroku: Press any key to open up the browser to login or q to exit:มาดูผลลัพธ์โดยกดปุ่มใดก็ได้บนแป้นพิมพ์ เมื่อกดปุ่มใด ๆ มันจะเปิดหน้า heroku login แล้วคลิกที่หน้า login จากนั้นเครื่อง local ของคุณจะเชื่อมต่อกับ Heroku server ระยะไกล ถ้าเชื่อมต่อสำเร็จ คุณจะเห็นสิ่งนี้:
asabeneh@Asabeneh:~$ heroku login
heroku: Press any key to open up the browser to login or q to exit:
Opening browser to https://cli-auth.heroku.com/auth/browser/be12987c-583a-4458-a2c2-ba2ce7f41610
Logging in... done
Logged in as asabeneh@gmail.com
asabeneh@Asabeneh:~$การสร้าง requirements และ Procfile
ก่อน push โค้ดไปยัง remote server เราต้องมีสิ่งเหล่านี้:
- requirements.txt
- Procfile
(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ pip freeze
Click==7.0
Flask==1.1.1
itsdangerous==1.1.0
Jinja2==2.10.3
MarkupSafe==1.1.1
Werkzeug==0.16.0
(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ touch requirements.txt
(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ pip freeze > requirements.txt
(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ cat requirements.txt
Click==7.0
Flask==1.1.1
itsdangerous==1.1.0
Jinja2==2.10.3
MarkupSafe==1.1.1
Werkzeug==0.16.0
(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ touch Procfile
(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ ls
Procfile env/ static/
app.py requirements.txt templates/
(env) asabeneh@Asabeneh:~/Desktop/python_for_web$Procfile จะมีคำสั่งที่รัน application บน web server ในกรณีของเราคือบน Heroku
web: python app.pyการ Push Project ไปยัง Heroku
ตอนนี้พร้อม deploy แล้ว ขั้นตอนการ deploy application บน Heroku:
- git init
- git add .
- git commit -m "commit message"
- heroku create 'name of the app as one word'
- git push heroku master
- heroku open (เพื่อเปิด application ที่ deploy แล้ว)
หลังจากขั้นตอนนี้ คุณจะได้ application เหมือน http://thirdaysofpython-practice.herokuapp.com/
แบบฝึกหัด: วันที่ 26
- คุณจะสร้าง application นี้ https://thirtydaysofpython-v1-final.herokuapp.com/ ส่วนที่เหลือคือ text analyser เท่านั้น