我主要是參考 Learn to build scalable web applications 這系列Section 3的部分,當初我看得時候可說是大受感動(?),第一次感受到專案目錄規劃的重要,我寫程式碼時因為大多只是寫來玩玩練習,因此都隨便放,總之能import到就可,老實說對專案目錄怎麼規劃沒太深的見解,從這支影片看到講師如此認真的講解目錄怎麼規劃,覺得以後應該要更認真看待這部分,若寫一個比較大型的程式,要有好的開始真的就要有好的目錄規劃,因此決定來記錄一下,當然目錄怎麼規劃沒有正解,畢竟要依需求來決定,但下面的做法還是不錯值得參考借鏡。
底下的文章有許多照搬的部分,所以其實大可直接去看影片 Section 3的部分,下面只是我的整理筆記。
好的目錄結構,能幫助我們管理與擴展,看起來也更加專業!
總之,先來看看專案目錄吧!
/project
— /app
— __init__.py
— home.py
— /framework
— __init__.py
— request_handler.py
— /models
— __init__.py
— /static
— /css
— /fonts
— /js
— /img
— /templates
— /commons
— navbar.html
— leftmenu.html
— /home
— home.html
— main.html
— app.yaml
— router.py
在專案第一層共有五個目錄,分別是 /app、/framework、/models、/static、/templates,與兩個檔案 app.yaml 和 router.py。
1. /app:request handlers
2. /framework:own custom request handler
3. /models:model of data using in datastore
4. /static:靜態檔案,例如 .css、.js、圖片媒體檔
5. /templates:網頁html檔
6. app.yaml:設定Google App Engine用
7. router.py:URL對映
先來看 app.yaml 與 router.py。
app.yaml:設定環境與URL對映handler
runtime: python27
api_version: 1
threadsafe: true
handlers:
- url: /favicon\.ico
static_files: favicon.ico
upload: favicon\.ico
- url: /static
static_dir: static ## 對映到專案裡的static目錄
- url: /.*
script: router.app
libraries:
- name: jinja2
version: latest
router.py:URL對映handler (做了兩次URL對映)
from webapp2 import WSGIApplication
from webapp2 import Route
app = WSGIApplication(
routes=[
Route('/', handler='main.MainPage'),
]
)
再來看看 handler 處理者的部分。
/framework/request_handler.py:建立custom request handler類別供/app裡的handler繼承,並在裡面實作常用之邏輯,如此能有效減少duplicate code的狀況,像是在 render template時,我們都會做傳入參數動態繪製html後再回覆給Client端,在這裡我們就將這些動作統一包裝成 render(self, template, **kwargs),/app裡的handler就可以呼叫 self.render()做這一系列的動作。
from webapp2 import RequestHandler
import os
import jinja2
class OurRequestHandler(RequestHandler):
template_directory = os.path.join(
os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)),
'templates')
jinja_enviroment = jinja2.Environment(
loader=jinja2.FileSystemLoader(template_directory)
)
def render(self, template, **kwargs):
jinja_template = self.jinja_enviroment.get_template(template)
html_from_template = jinja_template.render(**kwargs)
self.response.out.write(html_from_template)
* os.path.join(os.path.dirname(__file__), os.pardir) 等同目前檔案之上一目錄 (pardir = parent directory)。使用 os.path.abspath() 是確保路徑符合環境使用的路徑格式,像是本地端是windows路徑會是以 "\" 隔開,但在Linux會是 "/"。
* **kwargs能代表多個參數,會是 dictionary 格式。
/app/home.py:處理請求,以功能分類,像home.py存放跟首頁有關的請求,account.py就可以放跟帳號有關的請求等。
from framework.request_handler import OurRequestHandler
class Home(OurRequestHandler):
def get(self):
self.render('home/home.html')
/models就存放跟資料庫有關的model。
最後是網頁繪製的部分。
先來看看繪出來的home/home.html長怎樣。(先說一下,我不太會CSS)
應該大家都看過類似這樣結構的網頁,上方總會有navbar顯示網站名或搜尋引擎,而左邊有菜單能點選,比較會變動的只有白色內容的部分,像這樣的設計其實並不需要每一頁都寫程式碼,我們可以透過jinja2引擎動態繪製並組合各html,如此也能減少duplicate code的問題。
/templates/main.html:主頁面,組合了 commons/navbar.html、commons/leftmenu.html,並預留一{% block content %}可以填充。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{% block Title %}{% endblock %}</title>
<link rel="stylesheet" href="/static/css/bootstrap.min.css">
</head>
<body>
{% include "commons/navbar.html" %}
<div style="float: left">
{% include "commons/leftmenu.html" %}
</div>
<div>
{% block content %}
{% endblock %}
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
<script src="/static/js/bootstrap.min.js"></script>
</body>
</html>
* {% %}相關的都是跟jinja2有關的語法。
* "/static/..." 會從 app.yaml URL對映得知是要找專案裡static目錄下的檔案。
* https://developers.google.com/speed/libraries/ 提供許多常用的 js library。
* .css與.js檔有名的library取得許多都有提供CDN可以請求,如此可以減輕我們server的流量,個人是覺得有就用,但缺點是因為是第三方管理檔案,做了修改我們都是沒法掌握的,所以為求安定還是載下來放進專案存取比較保險,但應該有名的CDN資料安定性都值得信任。
/templates/home/home.html:{% extends "main.html" %}相當貼上main.html的內容,然後可以將包在 {% block content %}{% endblock %}中的內容插入main.html的{% block content %}中。
{% extends "main.html" %}
{% block Title %}Home{% endblock %}
{% block content %}
<h1>Hello World!</h1>
{% endblock %}
/templates/commons/navbar.html:<div style="background-color: pink; height: 100px;">
This is navbar
</div>
/templates/commons/leftmenu.html:<div style="background-color: blue; height: 600px">
This is leftmenu
</div>
大概就是這樣,整理下來再次覺得真的是很簡潔的寫法呢,可以減少許多原本需要重複程式碼的地方,第一次看到html組合起來的那部分,我還真有恍然大悟的感覺,原來可以這麼做!然後framework客製化request handler的部分也滿值得學習的,是平常寫程式就可以用到的概念。
沒有留言:
張貼留言