bessyhuang
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
      • Invitee
    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Versions and GitHub Sync Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
Invitee
Publish Note

Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

Your note will be visible on your profile and discoverable by anyone.
Your note is now live.
This note is visible on your profile and discoverable online.
Everyone on the web can find and read all notes of this public team.
See published notes
Unpublish note
Please check the box to agree to the Community Guidelines.
View profile
Engagement control
Commenting
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
  • Everyone
Suggest edit
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
Emoji Reply
Enable
Import from Dropbox Google Drive Gist Clipboard
   owned this note    owned this note      
Published Linked with GitHub
Subscribed
  • Any changes
    Be notified of any changes
  • Mention me
    Be notified of mention me
  • Unsubscribe
Subscribe
--- title: Use Django to create a website tags: Django, website --- # **Django 網站開發** > 【目次】 > [TOC] --- >Reference Website: >1. [Django documentation](https://docs.djangoproject.com/en/2.1/) >2. [Django Packages(可直接引用"功能套件",不用自己重複造)](https://djangopackages.org/) >3. [Stack Overflow (技術交流平台--寫程式遇到問題,用以尋求解答)](https://stackoverflow.com/) >4. [github (專案的免費開源分享空間--專案下載、協作)](https://github.com/) >5. [Model field reference](https://docs.djangoproject.com/en/2.1/ref/models/fields/) >6. [Making queries](https://docs.djangoproject.com/en/2.1/topics/db/queries/) >7. [Templates](https://docs.djangoproject.com/en/2.1/ref/templates/) --- ## **課程簡介與目標** * ==Django 是 **python** 實作而成的**網頁框架**== * 具備基本的 python 能力,並懂一點 HTML、CSS 與 Javascript * 建立簡單的靜態網頁,並加入動態資料 * 將網頁應用程式佈署到免費雲端空間 --- ## **網頁運作原理** * 一個網頁在運作時,主要有三項參與其中: 1. ==client(瀏覽器)== 2. ==web server(資料的運算和處理)== 3. ==database(儲存資料)== * 流程: ![](https://i.imgur.com/svkm2kX.png) > `client` 瀏覽器輸入網址 > ----> 網址會被路由器帶到正確的 `web server` 的位置 > ----> web server 接收到請求後,視其必要跟 `database` 索取資料 > > 索取 `database` 資料後 > ----> 經過 `web server` 對資料的運算和處理 > ----> 再把結果傳回 `client` 瀏覽器 --- ## **Django 基本介紹** * 誰使用 Django ? [Top 10 sites built with Django Framework:Instagram, Mozilla Firefox, Pinterest, NASA ... ](https://www.linkedin.com/pulse/top-10-sites-built-django-framework-vladimir-bogdanov) * ==Django 特點== * 歷史悠久,經得起考驗。 (首次發行:2005年7月) * 市佔率最高 * 最完整的技術文件 * 豐富的套件 * 強大的社群 (當開發上遇到困難,都能快速的找到解決方法) * 提供 total solution,初學者可透過 Django 內建的模塊了解網站運作。(包山包海的套件,已內建 各種網站運作需要的模塊) --- ![](https://i.imgur.com/6sggp48.png) | ==**知名の Python 網頁框架**== | 特點 | 備註 | | ------- | ------------------------| ---------------------------------- | | Django | 大而全,內建全套解決方案 | 讓初學者能專注搞懂如何運作,就能快速開發網站 | | Flask | 微框架,輕盈,簡單 | 適用時機:小專案 | | Tornado | 微框架,少而精,non-blocking network IO | 可實現異步操作 | | Pyramid | 注重靈活性,所有模塊都需另外找套件搭配運用 | Django 的相反版本,適合"不喜歡被某個套件綁住的人使用" | --- * Django 的原理與架構 ![](https://i.imgur.com/5RhrIoK.png) * ==Django 存放在 web server== * MTV * ==Models(定義資料庫的結構,e.g.XX資料表中,有XX欄位.欄位長度.是否可為空值...)== * ==Templates(最後的 HTML 呈現)== * ==Views(資料的邏輯運算)== * Browser --> URLS --> Views --> Models ---(ORM 語法)---> Database --> Models --> Views --> Templates --> Browser * Why MTV ? * 把 Models, Templates, Views 做切割 * 避免 Spaghetti Code (捲成一團) 1. 分離商業邏輯(後端)與UI(前端) 2. 前後端可獨立作業 3. 擁有更多彈性 4. 較容易維護 5. 降低複雜度 > ==傳統 ---> 把 Models, Templates, Views 寫在同一支程式中,造成混亂和維護困難== --- :::info ### **Step00:搭建 python3 虛擬環境** > * 把它想像成 --- ==完全獨立且隔絕的作業環境== > 專門給這個專案使用の > 完全不會跟原本的作業環境有衝突 > * why 虛擬環境? > * 假設"現在"作業環境中的套件是"最新的版本",但此專案卻需要舊的版本。 > * ~~把新的版本降為舊的版本~~ ==新建 Django 專案資料夾== * myproject 代換為你所想命名的"資料夾名稱" ``` ~$ mkdir myproject_test ~$ cd myproject_test ``` ==在 Django 專案資料夾中,建立 python3 虛擬環境== * venv 套件 * py3env 代換為你所想命名的"虛擬環境名稱" * 啟動 python3 虛擬環境的資料夾 ``` (linux/mac) ~/myproject_test$ python3 -m venv py3env (windows) C:\Python35\python -m venv myvenv ``` ==啟動虛擬環境== * 出現 (py3env) --> 成功 * 關閉虛擬環境: * ~/myproject_test$ deactivate * (py3env) 消失了~ ``` (linux/mac) ~/myproject_test$ source py3env/bin/activate (windows) py3env/Scripts/activate ``` --- ### **Step01:在 python3 虛擬環境下,安裝 Django** ==下載與安裝 Django== * 若要安裝 Django 的某個特定版本 * ```pip install Django==1.9.10``` * ```pip install Django``` ``` ~/myproject_test$ pip install Django==1.9.10 ``` * ```pip freeze``` 檢查當前的 Django 版本 ``` ~/myproject_test$ pip freeze ``` ::: --- # **在本關卡中會學習到什麼** * Django 網站開發:快速打造完美網頁應用程式 * 自己打造專屬の==記帳 app== --- # **Step1:建立 Django の project** ## **project 與 apps** 把一個 ==project 專案== 想像成 ==一個網站== * 以 project 為最上層單位,==一個 project 可以包含多個 app== * What is app? * 代表 ==同一個網站中,不同的功能模塊== * 如同 樂高積木,可隨時擴充、拔脫,也可把 app 拿去給別的 project 使用 * 使用時機:一個論壇類型的網站可能會有會員管理功能、語音內容區塊、文字內容區塊...等,可建立不同的 app 來管理。 ``` django-admin startproject project_chia . ``` * project_chia 代換為 你所想命名的"資料夾名稱" * . 代表 在當下的位置 ![](https://i.imgur.com/Lcc5dRA.png) ```htmlembedded= (py3env) testchia@fengchia-swift-sf314-52:~/myproject_test$ ls py3env (py3env) testchia@fengchia-swift-sf314-52:~/myproject_test$ django-admin startproject project_chia . (py3env) testchia@fengchia-swift-sf314-52:~/myproject_test$ ls manage.py project_chia py3env (py3env) testchia@fengchia-swift-sf314-52:~/myproject_test$ cd project_chia (py3env) testchia@fengchia-swift-sf314-52:~/myproject_test/project_chia$ ls __init__.py settings.py urls.py wsgi.py ``` >![](https://i.imgur.com/AzNnim2.png) > >**解釋各個 .py 的作用:** >* manage.py:跟 django-admin 幾乎是一模一樣的功能,它是一個管理器。很多功能都需要透過這個管理器來執行。 >* project_chia 資料夾底下有 settings.py、urls.py、wsgi.py、init.py > * settings.py:Django 中各種環境設定 > * urls.py:根據瀏覽器輸入的**網址**,指派 views.py 底下的哪一支程式來做事情 > * wsgi.py:web server 跟網頁應用程式(django)之間如何做溝通 > * init.py:讓 project_chia 變成一個套件模組 --- # **Step2:Project 參數設定介紹** ## 編輯 settings.py * [Sublime Text 3 編輯器](https://www.sublimetext.com/3) ```python= # 這些 app 是 Django 內建的 app , # 亦即"一個 project 可包含多個 app" の app INSTALLED_APPS = [ 'django.contrib.admin', #後台管理系統 'django.contrib.auth', #權限的管控 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', #我們要建立static資料夾 ] TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', #DjangoTemplates-->我們要建立Templates資料夾 'DIRS': [], #定義templates的路徑,它是一個list 'APP_DIRS': True, #當我們以後在project底下建立app之後,Django會自動探索app底下是否有templates的資源 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', #sqlite3是Django裡預設的資料庫 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), #最後會產生db.sqlite3的檔案 } } TIME_ZONE = 'UTC' #時區:世界標準時間 * 改為--->TIME_ZONE = 'Asia/Taipei' #時區:台北 STATIC_URL = '/static/' #存取靜態資源(CSS, JavaScript, Images) ``` ## 為 project 建立專屬資料庫 * 回到 manage.py 所在的位置,再執行 ```python manage.py migrate``` * 資料的寫進寫出,都是與 db.sqlite3 做互動 * 與資料庫結構相關的檔案,還有 models.py (之後會使用到~先記在腦袋裡) ![](https://i.imgur.com/5OtMCMF.png) ```htmlmixed= (py3env) testchia@fengchia-swift-sf314-52:~/myproject_test/project_chia$ ls __init__.py settings.py urls.py wsgi.py (py3env) testchia@fengchia-swift-sf314-52:~/myproject_test/project_chia$ cd .. (py3env) testchia@fengchia-swift-sf314-52:~/myproject_test$ ls manage.py project_chia py3env (py3env) testchia@fengchia-swift-sf314-52:~/myproject_test$ python manage.py migrate Operations to perform: Apply all migrations: contenttypes, auth, admin, sessions Running migrations: Rendering model states... DONE Applying contenttypes.0001_initial... OK ... Applying sessions.0001_initial... OK (py3env) testchia@fengchia-swift-sf314-52:~/myproject_test$ ls db.sqlite3 manage.py project_chia py3env ``` ## 建立app * 回到 manage.py 所在的位置,再執行 ```python manage.py startapp chia_app``` ![](https://i.imgur.com/BFmUksF.png) ```htmlmixed= (py3env) testchia@fengchia-swift-sf314-52:~/myproject_test$ python manage.py startapp chia_app (py3env) testchia@fengchia-swift-sf314-52:~/myproject_test$ ls chia_app db.sqlite3 manage.py project_chia py3env ``` >![](https://i.imgur.com/4pWdhga.png) > >**解釋各個 .py 的作用:** >* chia_app 資料夾底下有 models.py、migrations (資料夾)、admin.py、views.py、tests.py、apps.py、init.py > * models.py: > * 把它當作一個空的 database > * 設定 database 的結構:可建立一個一個的 table,每個 table 中又有好幾個 column > * migrations (資料夾):每當我們對 models.py 做修改,紀錄修改 database 的歷史步驟,還有版本控制的功能 > * admin.py:後台管理介面的管理程式。 > * 打開後台管理介面針對 models.py 中所定義的 table 做其內容的 "新增/修改/刪除" > * views.py:定義各種邏輯運算 > * tests.py:方便我們測試的檔案 > * apps.py:針對 app 的組態管理,存放這支 app 的 meta 檔案(目前比較不會用到) --- # Step3:製作網頁的第一步:利用 Django 生成靜態網頁 ## **在本關卡中會學習到什麼** * 初步熟悉 Django 的 MTV 架構 * 使用 Django 生成簡單的靜態網頁 * 靜態網頁: 先不跟 database 做互動,只做單純的展示功能。資料寫死在 HTML 中。 --- ## 建立一個簡單的靜態網頁 * 打開 Sublime Text 3 ,建立 example_hello.html * 路徑:/home/testchia/myproject_test/example_hello.html ```htmlmixed= <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Example_chia</title> </head> <body> <h1>Hello Django 0.0</h1> </body> </html> ``` --- ## Url Dispatcher - 如何解析使用者於瀏覽器輸入的 url * Url Dispatcher:使用 urls.py * urls.py 用來解析使用者於瀏覽器輸入的 url * 根據解析後的結果,去指派某一支特定的程式來做運作 ### ==urls.py== ```python= from django.conf.urls import url from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), #若輸入的網址符合 admin/ 的patterns,才會指派admin.site.urls這支程式來運作 => 開啟後台管理介面 #admin.site.urls這支程式 --> django內建之名稱為admin的apps其底下有一支程式叫site,site.py裡面有一個叫urls的function ] ``` :::danger * Regular Expression: * ```^```: 以什麼為開頭 * ```$```: 以什麼為結尾 * ```.```: 任意字元 * ```+```: 一個字元以上 * ```?```: 是否有某個字元出現都可以 * ```\d```: 數字 * ```()```: 擷取符合的 pattern ::: * 回到 manage.py 所在的位置,再執行 ```python manage.py runserver``` ```htmlmixed= (py3env) testchia@fengchia-swift-sf314-52:~/myproject_test$ python manage.py runserver Performing system checks... System check identified no issues (0 silenced). August 31, 2018 - 16:21:17 Django version 1.9.10, using settings 'project_chia.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CONTROL-C. Not Found: / [31/Aug/2018 16:21:20] "GET / HTTP/1.1" 200 1767 Not Found: /favicon.ico [31/Aug/2018 16:21:20] "GET /favicon.ico HTTP/1.1" 404 1942 ``` * http://127.0.0.1:8000/ ---> http://127.0.0.1 網頁伺服器現在搭建在"本機端localhost的電腦" ---> :8000/ 由於本機端裝有各式各樣的應用,這邊就必須指定其中一個入口(專門給 Django 使用) * 若想更改原本預設的 port 為 8001,並 runserver * ```python manage.py runserver 8001``` * ```127.0.0.1:8001/admin``` ![](https://i.imgur.com/xDzYZPm.png) --- ## Url Dispatcher and View - Django 如何根據 url 指派正確的 view 程式運行 * Url Dispatcher:使用 views.py ### ==urls.py== [方法一] 效能好 ```python= from django.conf.urls import url from django.contrib import admin from chia_app import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^hello/', views.hello), ] ``` [方法二] 效能差一點,因為 Django 需要另外去解析 ```python= from django.conf.urls import url from django.contrib import admin #from chia_app import views urlpatterns = [ url(r'^admin/', admin.site.urls), #url(r'^hello/', views.hello), url(r'^hello/', 'chia_app.views.hello'), ] ``` ### ==views.py== ```python= from django.shortcuts import render, HttpResponse # Create your views here. def hello(request): return HttpResponse('HELLO 0.0') ``` ![](https://i.imgur.com/IZl9p5Q.png) ## Views and Templates - 用 Django 生成靜態網頁 * 用 render 來達成 Views 和 Templates 的溝通 * 將之前寫的 example_hello.html 放入 templates 資料夾 * 路徑:/home/testchia/myproject_test/chia_app/templates/app/example_hello.html * 改寫 views.py * 在 settings.py 加入 chia_app ```python= (py3env) testchia@fengchia-swift-sf314-52:~/myproject_test$ cd chia_app (py3env) testchia@fengchia-swift-sf314-52:~/myproject_test/chia_app$ mkdir templates (py3env) testchia@fengchia-swift-sf314-52:~/myproject_test/chia_app$ cd templates (py3env) testchia@fengchia-swift-sf314-52:~/myproject_test/chia_app/templates$ mkdir app ``` ### ==views.py== ```python= from django.shortcuts import render, HttpResponse # Create your views here. def hello(request): return render(request,'app/example_hello.html',{}) ``` ### ==settings.py== ```python= INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'chia_app', ] ``` ![](https://i.imgur.com/hHuOfID.png) ## static 資料夾 - 裝飾網頁 * [使用 bootstrap 的免費模板](https://getbootstrap.com/docs/4.1/examples/) ---> download "Dashboard" 並修改它 * bootstrap 是免費的 CSS, JavaScript 的資源套件,我們可以把它 download 並套用 ![](https://i.imgur.com/xHBoYFH.png) ### ==擺放位置== 1. 找到 "Dashboard" 所在的位置:/home/testchia/下載/bootstrap-4.1.3/site/docs/4.1/examples/dashboard 2. 將 index.html 移至 /home/testchia/myproject_test/chia_app/templates/app/index.html 3. 將 dashboard.css 移至 /home/testchia/myproject_test/chia_app/static/css/dashboard.css ```htmlmixed= (py3env) testchia@fengchia-swift-sf314-52:~/myproject_test$ cd chia_app (py3env) testchia@fengchia-swift-sf314-52:~/myproject_test/chia_app$ mkdir static (py3env) testchia@fengchia-swift-sf314-52:~/myproject_test/chia_app$ cd static (py3env) testchia@fengchia-swift-sf314-52:~/myproject_test/chia_app/static$ mkdir css ``` 4. 放置 bootstrap.min.css 到路徑:/home/testchia/myproject_test/chia_app/static/css/bootstrap.min.css ### ==urls.py== ```python= from django.conf.urls import url from django.contrib import admin from chia_app import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^hello/', views.hello), url(r'^$', views.frontpage), ] ``` ### ==views.py== ```python= from django.shortcuts import render, HttpResponse # Create your views here. def hello(request): return render(request,'app/example_hello.html',{}) def frontpage(request): return render(request,'app/index.html',{}) ``` ### ==修改路徑 index.html== [方法一] (寫死的方式) ```htmlmixed= <link rel="icon" href="../../../../favicon.ico"> #刪除 <!-- Bootstrap core CSS --> <link href="static/css/bootstrap.min.css" rel="stylesheet"> <!-- Custom styles for this template --> <link href="static/css/dashboard.css" rel="stylesheet"> ``` [方法二] (有彈性的方式) ```htmlmixed= {% load staticfiles %} #加上 <link rel="icon" href="../../../../favicon.ico"> #刪除 <!-- Bootstrap core CSS --> <!-- Bootstrap core CSS --> <link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet"> <!-- Custom styles for this template --> <link href="{% static 'css/dashboard.css' %}" rel="stylesheet"> ``` ![](https://i.imgur.com/sDQVxjP.png) --- # Step4:利用 Django 製作動態網頁 --- 以記帳本網頁應用程式為例 ## **在本關卡中會學習到什麼** * 使用動態資料產生網頁內容 * 製作可互動的網頁 * 動態網頁:跟 database 做互動。 --- ## Model - 操作資料庫結構 * 使用 Django 的 Model 定義資料庫結構 ### ==models.py== * 一個 ==類別(class)== 就是 ==1個table== * 本專案需要 2 個 table: * 紀錄(欄位包含:日期、描述、分類、金額、收支) * 分類設定(欄位包含:分類自己本身 ---> 自己輸入的分類) ```python= from django.db import models from django.db.models import CharField,DateField,ForeignKey,IntegerField # Create your models here. BALANCE_TYPE = ((u'收入',u'收入'),(u'支出',u'支出')) #元組 tuple:可以視為不可改變的串列 ((key,value),(key,value)) class Category(models.Model): category = CharField(max_length=20) class Record(models.Model): date = DateField() description = CharField(max_length=300) category = ForeignKey(Category,on_delete=models.SET_NULL,null=True) #外來鍵是一個(或數個)指向另外一個表格主鍵的欄位。 cash = IntegerField() balance_type= CharField(max_length=2,choices=BALANCE_TYPE) #收/支choices只有兩種,已定義在上方的BALANCE_TYPE ``` * [元組 tuple:可以視為不可改變的串列](https://blog.kdchang.cc/2017/08/15/learning-programming-and-coding-with-python-list-tuple-dict-set/) * 元組比起串列好處: * 佔用空間較少 * 可以當做字典的 key(因不可變) * 具名 tuple 可當做物件替代 * 當做函式引數 * [Python 的編碼](https://openhome.cc/Gossip/Encoding/Python.html) :::danger * 示範專案用到的 Model field types: * ```models.CharField``` : varchar * ```models.IntegerField``` : int * ```models.DateField``` : date * ```models.ForeignKey``` : foreign key * ForeignKey 在資料庫中當作 Constraint 使用 * https://www.1keydata.com/tw/sql/sql-foreign-key.html * http://www.w3school.com.cn/sql/sql_foreignkey.asp * ForeignKey 的 on_delete 參數: * models.CASCADE:相關的資料,全部都會被刪除 * models.PROTECT:不允許某個資料被刪除 * models.SET_NULL:要搭配 null = True。被刪除的,會被設成 None * models.SET_DEFAULT:要搭配 default。被刪除的,會被設成預設的 未分類 * models.SET():要傳入 function ::: ## Model - 操作資料庫的版本控制 - migrations 資料夾 * 理解 migrations 的用法與意義 * 回到 manage.py 所在的位置,再執行 * 建立 migrations 腳本 (此操作 尚未更動資料庫) ```python manage.py makemigrations [app]``` > 出現 0001_initial.py 腳本檔案(版本): /home/testchia/myproject_test/chia_app/migrations/0001_initial.py * 執行腳本 (此操作 更動資料庫) ```python manage.py migrate [chia_app]``` * 退回特定版本 (使用時機:當後悔更動資料庫時) ```python manage.py migrate [chia_app] [migrate version(0001_initial -->想要退回的版本名稱)]``` ## 操作網頁 後台管理介面 * 使用後台管理介面可輕鬆管理資料庫內容 ### ==建立 Super user 帳號、密碼== * 回到 manage.py 所在的位置,再執行 ```python manage.py createsuperuser``` * 統一建立 帳號:admin 密碼:@@12345678 ```python manage.py runserver``` ### ==admin.py== * 要先到 admin.py 註冊 models.py 上面所寫的 2 個 table,這樣才能在後台管理介面中做內容的編輯 ```python= from django.contrib import admin from .models import Record, Category # Register your models here. admin.site.register(Record) admin.site.register(Category) ``` ### 進入後台管理介面 ![](https://i.imgur.com/mMR7vJv.png) ![](https://i.imgur.com/3wmRlFs.png) ![](https://i.imgur.com/fthjTkB.png) ### 在==models.py==中定義,將後台管理介面的英文顯示,變成中文 ```python= from django.db import models from django.db.models import CharField,DateField,ForeignKey,IntegerField # Create your models here. BALANCE_TYPE = ((u'收入',u'收入'),(u'支出',u'支出')) #元組 tuple:可以視為不可改變的串列 ((key,value),(key,value)) class Category(models.Model): category = CharField(max_length=20) def __str__(self): return self.category class Record(models.Model): date = DateField() description = CharField(max_length=300) category = ForeignKey(Category,on_delete=models.SET_NULL,null=True) #外來鍵是一個(或數個)指向另外一個表格主鍵的欄位。 cash = IntegerField() balance_type= CharField(max_length=2,choices=BALANCE_TYPE) #收/支choices只有兩種,已定義在上方的BALANCE_TYPE def __str__(self): return self.description ``` ![](https://i.imgur.com/xnBmb87.png) ![](https://i.imgur.com/5yW0uq9.png) ## Django ORM 語法 -- 操作資料庫中的資料 * [教學影片:6-5.Django ORM語法操作資料庫中的資料.mp4](https://drive.google.com/file/d/1E68XUj3PjQgXuu0cI0LJIMYlE-xnKKwW/view) * 學習透過 Django ORM 與資料庫對話 ![](https://i.imgur.com/zm7hODp.png) ![](https://i.imgur.com/1zSv4bm.png) ![](https://i.imgur.com/OrIGPlW.png) ![](https://i.imgur.com/VHzpUCZ.png) ```python= >>> dir(r_get) #不能再做其他query的動作 >>> dir(r_filter) #可再做其他query的動作 >>> r_filter[0] >>> r_filter[0] == r_get ``` ![](https://i.imgur.com/uF9Pq9f.png) ![](https://i.imgur.com/z5CqYYn.png) ## MTV 協作 - 使用資料庫內的動態資料渲染網頁 * 理解 MTV 之間如何協調溝通,使用動態資料(資料庫中的資料)生成網頁內容。 ### ==修改 index.html== ```htmlmixed= {% load staticfiles %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags --> <meta name="description" content=""> <meta name="author" content=""> <title>Dashboard Template for Bootstrap</title> <!-- Bootstrap core CSS --> <link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet"> <!-- Custom styles for this template --> <link href="{% static 'css/dashboard.css' %}" rel="stylesheet"> </head> <body> <nav class="navbar navbar-dark fixed-top bg-dark flex-md-nowrap p-0 shadow"> <a class="navbar-brand col-sm-3 col-md-2 mr-0" href="#">My Project</a> <ul class="navbar-nav px-3"> <li class="nav-item text-nowrap"> <a class="nav-link" href="/accounts/logout">Logout</a> </li> </ul> </nav> <div class="container-fluid"> <div class="row"> <nav class="col-md-2 d-none d-md-block bg-light sidebar"> <div class="sidebar-sticky"> <ul class="nav flex-column"> <li class="nav-item"> <a class="nav-link active" href="#"> <span data-feather="home"></span> 帳務總覽<span class="sr-only">(current)</span> </a> </li> <li class="nav-item"> <a class="nav-link" href="#"> <span data-feather="file"></span> 設定 </a> </li> </ul> </div> </nav> <main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-4"> <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"> <h1 class="page-header">帳務總覽</h1> </div> <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> <div class="row placeholders"> <div class="col-xs-8 col-sm-4 placeholder"> <h3>收入</h3> <span class="text-muted"><h2>{{ income }}</h2></span> </div> <div class="col-xs-8 col-sm-4 placeholder"> <h3>支出</h3> <span class="text-muted"><h2><font color="#DF565C">{{ outcome }}</font></h2></span> </div> <div class="col-xs-8 col-sm-4 placeholder"> <h3>存款</h3> <span class="text-muted"><h2><font color="#53DF7D">{{ net }}</font></h2></span> </div> </div> </div> </main> <main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-4"> <h2 class="sub-header">歷史記錄</h2> <div class="table-responsive"> <table class="table table-striped table-sm"> <thead> <tr> <th>日期</th> <th>描述</th> <th>分類</th> <th>金額</th> <th>收/支</th> </tr> </thead> <tbody> </tbody> </table> </div> </main> </div> </div> <!-- Bootstrap core JavaScript ================================================== --> </body> </html> ``` ### ==urls.py== * chia_app 底下的 urls.py(將 urls.py 複製並新增至 chia_app 底下),路徑:/home/testchia/myproject_test/chia_app/urls.py ```python= from django.conf.urls import url from . import views urlpatterns = [ url(r'^$', views.frontpage), ] ``` * project_chia 底下的 urls.py,路徑:/home/testchia/myproject_test/project_chia/urls.py ```python= """project_chia URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/1.9/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.conf.urls import url, include 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) """ from django.conf.urls import url, include from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^', include('chia_app.urls')), ] ``` ### ==index.html== * The Django template language * Variables:```{{ variable }}``` * Tags:```{% tag %}``` 處理邏輯的部份 :::warning > ``` > {{ records }} > ``` > ![](https://i.imgur.com/Rl8W0D5.png) > ![](https://i.imgur.com/aP5UoAZ.png) ::: :::info > ``` > {% for record in records %} > <tr> > <td>{{ record.date }}</td> > <td>{{ record.description }}</td> > <td>{{ record.category }}</td> > <td>{{ record.cash }}</td> > <td>{{ record.balance_type }}</td> > </tr> > {% endfor %} > ``` > ![](https://i.imgur.com/j0JLxxB.png) > ![](https://i.imgur.com/h55xEQW.png) ::: :::success > ``` > {% for record in records %} > <tr> > <td>{{ record.date | date:"Y-m-d"}}</td> > <td>{{ record.description }}</td> > <td>{{ record.category }}</td> > <td>{{ record.cash }}</td> > <td>{{ record.balance_type }}</td> > </tr> > {% endfor %} > ``` > ![](https://i.imgur.com/p9NLLNb.png) > ![](https://i.imgur.com/Hy0YmXy.png) ::: ### ==views.py== ```python= from django.shortcuts import render, HttpResponse from .models import Record # Create your views here. def hello(request): return render(request,'app/example_hello.html',{}) def frontpage(request): records = Record.objects.filter() income_list = [record.cash for record in records if record.balance_type == '收入'] outcome_list = [record.cash for record in records if record.balance_type == '支出'] income = sum(income_list) if len(income_list)!=0 else 0 outcome = sum(outcome_list) if len(outcome_list)!=0 else 0 net = income - outcome return render(request,'app/index.html',{'records':records,'income':income,'outcome':outcome,'net':net}) #可改寫成 return render(request,'app/index.html',locals()) ``` ![](https://i.imgur.com/3be1qTS.png) # Step5:Template - 模版繼承避免重複的 HTML code ## ==base.html== ```htmlmixed= {% load staticfiles %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags --> <meta name="description" content=""> <meta name="author" content=""> <title>Dashboard Template for Bootstrap</title> <!-- Bootstrap core CSS --> <link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet"> <!-- Custom styles for this template --> <link href="{% static 'css/dashboard.css' %}" rel="stylesheet"> </head> <body> <nav class="navbar navbar-dark fixed-top bg-dark flex-md-nowrap p-0 shadow"> <a class="navbar-brand col-sm-3 col-md-2 mr-0" href="#">My Project</a> <ul class="navbar-nav px-3"> <li class="nav-item text-nowrap"> <a class="nav-link" href="/accounts/logout">Logout</a> </li> </ul> </nav> {% block content %} {% endblock %} <!-- Bootstrap core JavaScript ================================================== --> </body> </html> ``` ## ==index.html== ```htmlmixed= {% extends 'app/base.html' %} {% block content %} <div class="container-fluid"> <div class="row"> <nav class="col-md-2 d-none d-md-block bg-light sidebar"> <div class="sidebar-sticky"> <ul class="nav flex-column"> <li class="nav-item"> <a class="nav-link active" href="/"> <span data-feather="home"></span> 帳務總覽<span class="sr-only">(current)</span> </a> </li> <li class="nav-item"> <a class="nav-link" href="/settings"> <span data-feather="file"></span> 設定 </a> </li> </ul> </div> </nav> <main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-4"> <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"> <h1 class="page-header">帳務總覽</h1> </div> <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> <div class="row placeholders"> <div class="col-xs-8 col-sm-4 placeholder"> <h3>收入</h3> <span class="text-muted"><h2>{{ income }}</h2></span> </div> <div class="col-xs-8 col-sm-4 placeholder"> <h3>支出</h3> <span class="text-muted"><h2><font color="#DF565C">{{ outcome }}</font></h2></span> </div> <div class="col-xs-8 col-sm-4 placeholder"> <h3>存款</h3> <span class="text-muted"><h2><font color="#53DF7D">{{ net }}</font></h2></span> </div> </div> </div> </main> <main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-4"> <h2 class="sub-header">歷史記錄</h2> <div class="table-responsive"> <table class="table table-striped table-sm"> <thead> <tr> <th>日期</th> <th>描述</th> <th>分類</th> <th>金額</th> <th>收/支</th> </tr> </thead> <tbody> {% for record in records %} <tr> <td>{{ record.date | date:"Y-m-d"}}</td> <td>{{ record.description }}</td> <td>{{ record.category }}</td> <td>{{ record.cash }}</td> <td>{{ record.balance_type }}</td> </tr> {% endfor %} </tbody> </table> </div> </main> </div> </div> {% endblock %} ``` # Step6:製作 settings.html 設定的頁面 ## chia_app 底下的 ==urls.py== ```python= from django.conf.urls import url from . import views urlpatterns = [ url(r'^$', views.frontpage), url(r'^settings$', views.settings), ] ``` ## ==views.py== ```python= from django.shortcuts import render, HttpResponse from .models import Record # Create your views here. def hello(request): return render(request,'app/example_hello.html',{}) def frontpage(request): records = Record.objects.filter() income_list = [record.cash for record in records if record.balance_type == '收入'] outcome_list = [record.cash for record in records if record.balance_type == '支出'] income = sum(income_list) if len(income_list)!=0 else 0 outcome = sum(outcome_list) if len(outcome_list)!=0 else 0 net = income - outcome return render(request,'app/index.html',locals()) def settings(request): return render(request,'app/settings.html',{}) ``` ## ==settings.html== ```htmlmixed= {% extends 'app/base.html' %} {% block content %} <div class="container-fluid"> <div class="row"> <nav class="col-md-2 d-none d-md-block bg-light sidebar"> <div class="sidebar-sticky"> <ul class="nav flex-column"> <li class="nav-item"> <a class="nav-link active" href="/"> <span data-feather="home"></span> 帳務總覽<span class="sr-only">(current)</span> </a> </li> <li class="nav-item"> <a class="nav-link" href="/settings"> <span data-feather="file"></span> 設定 </a> </li> </ul> </div> </nav> <main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-4"> <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3"> <h1 class="page-header">分類設定</h1> </div> <table class="table table-scrollable"> <thead> <tr> <th>分類</th> </tr> </thead> <tbody> <td> </td> </tbody> </table> </main> </div> </div> {% endblock %} ``` :::warning > ``` > <tbody> > {% for category in categories %} > <td>{{ category.category }}</td> > {% endfor %} > </tbody> > ``` > ![](https://i.imgur.com/Fr3e2CI.png) > ![](https://i.imgur.com/O5eI90v.png) ::: ## Form - 利用 HTML 表單與網頁產生互動 * 透過操作表單讓使用者可以新增、刪除資料庫內的資料,並讓網頁產生改變。 ### ==settings.html== ```htmlmixed= {% extends 'app/base.html' %} {% block content %} <div class="container-fluid"> <div class="row"> <nav class="col-md-2 d-none d-md-block bg-light sidebar"> <div class="sidebar-sticky"> <ul class="nav flex-column"> <li class="nav-item"> <a class="nav-link active" href="/"> <span data-feather="home"></span> 帳務總覽<span class="sr-only">(current)</span> </a> </li> <li class="nav-item"> <a class="nav-link" href="/settings"> <span data-feather="file"></span> 設定 </a> </li> </ul> </div> </nav> <main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-4"> <div class="d-flex flex-wrap justify-content-between flex-md-nowrap align-items-center pt-3 pb-2 mb-3"> <h1 class="page-header">分類設定</h1> </div> <form action="/add_category" method="post"> {% csrf_token %} <input type="text" name="add_category_name"> <input type="submit" value="新增分類" class="btn"> </form> <br/> <table class="table table-scrollable"> <thead> <tr> <th>分類</th> </tr> </thead> <tbody> {% for category in categories %} <td> <div class="col-8 .col-sm-6">{{ category.category }}</div> <div class="col-8 .col-sm-6"><a href="/delete_category/{{ category.category }}">刪除</a></div> </td> {% endfor %} </tbody> </table> </main> </div> </div> {% endblock %} ``` ## ==urls.py== ```python= om django.conf.urls import url from . import views urlpatterns = [ url(r'^$', views.frontpage), url(r'^settings$', views.settings), url(r'^add_category$', views.addCategory), url(r'^delete_category/(?P<category>\w+)',views.deleteCategory) ] ``` ## ==views.py== ```python= from django.shortcuts import render, HttpResponse, redirect from .models import Record, Category # Create your views here. def hello(request): return render(request,'app/example_hello.html',{}) def frontpage(request): records = Record.objects.filter() income_list = [record.cash for record in records if record.balance_type == '收入'] outcome_list = [record.cash for record in records if record.balance_type == '支出'] income = sum(income_list) if len(income_list)!=0 else 0 outcome = sum(outcome_list) if len(outcome_list)!=0 else 0 net = income - outcome return render(request,'app/index.html',locals()) def settings(request): categories = Category.objects.filter() return render(request,'app/settings.html',locals()) def addCategory(request): if request.method == 'POST': posted_data = request.POST category = posted_data['add_category_name'] Category.objects.get_or_create(category=category) return redirect('/settings') def deleteCategory(request,category): Category.objects.filter(category=category).delete() return redirect('/settings') ``` ![](https://i.imgur.com/e9c2ktn.png) # Step7:Form - 利用 Django 表單物件替代 HTML 表單(使用 ModelForm) ![](https://i.imgur.com/WbyakKS.png) ## chia_app 底下新增 ==forms.py== * forms.py 路徑:/home/testchia/myproject_test/chia_app/forms.py ```python= from django.forms import ModelForm from .models import Record class RecordForm(ModelForm): class Meta: model = Record fields = ['date','description','category','cash','balance_type'] ``` ## ==index.html== ```htmlmixed= {% extends 'app/base.html' %} {% block content %} <div class="container-fluid"> <div class="row"> <nav class="col-md-2 d-none d-md-block bg-light sidebar"> <div class="sidebar-sticky"> <ul class="nav flex-column"> <li class="nav-item"> <a class="nav-link active" href="/"> <span data-feather="home"></span> 帳務總覽<span class="sr-only">(current)</span> </a> </li> <li class="nav-item"> <a class="nav-link" href="/settings"> <span data-feather="file"></span> 設定 </a> </li> </ul> </div> </nav> <main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-4"> <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"> <h1 class="page-header">帳務總覽</h1> </div> <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> <div class="row placeholders"> <div class="col-xs-8 col-sm-4 placeholder"> <h3>收入</h3> <span class="text-muted"><h2>{{ income }}</h2></span> </div> <div class="col-xs-8 col-sm-4 placeholder"> <h3>支出</h3> <span class="text-muted"><h2><font color="#DF565C">{{ outcome }}</font></h2></span> </div> <div class="col-xs-8 col-sm-4 placeholder"> <h3>存款</h3> <span class="text-muted"><h2><font color="#53DF7D">{{ net }}</font></h2></span> </div> </div> </div> </main> <main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-4"> <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"> <h2 class="sub-header">新增紀錄</h3> </div> <div class="table-responsive"> <form action="/add_record" method="post"> {% csrf_token %} <table class="table table-striped"> <col style="width:15%"> <col style="width:35%"> <col style="width:20%"> <col style="width:18%"> <col style="width:7%"> <thead> <tr> <th>日期</th> <th>描述</th> <th>分類</th> <th>金額</th> <th>收支</th> </tr> </thead> <tbody> <tr> {% for field in record_form %} <td>{{ field }}</td> {% endfor %} </tr> </tbody> </table> <div class="right-area"> <input type="submit" class="btn show-new-item" value="新增紀錄" /> </div> </form> </div> </main> <main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-4"> <h2 class="sub-header">歷史記錄</h2> <div class="table-responsive"> <table class="table table-striped table-sm"> <thead> <tr> <th>日期</th> <th>描述</th> <th>分類</th> <th>金額</th> <th>收/支</th> </tr> </thead> <tbody> {% for record in records %} <tr> <td>{{ record.date | date:"Y-m-d"}}</td> <td>{{ record.description }}</td> <td>{{ record.category }}</td> <td>{{ record.cash }}</td> <td>{{ record.balance_type }}</td> </tr> {% endfor %} </tbody> </table> </div> </main> </div> </div> {% endblock %} ``` ## ==dashboard.css== ```css= .right-area { float: right; z-index: 2; vertical-align: middle; display: inline-block; margin-top: -15px; } .left-area { float: left; margin-left: 3px; z-index: 2; vertical-align: middle; display: inline-block; margin-top: -15px; } form input { width: 100%; } ``` ## ==views.py== ```python= from django.shortcuts import render, HttpResponse, redirect from .models import Record, Category from .forms import RecordForm # Create your views here. def hello(request): return render(request,'app/example_hello.html',{}) def frontpage(request): record_form = RecordForm(initial={'balance_type':'支出'}) records = Record.objects.filter() income_list = [record.cash for record in records if record.balance_type == '收入'] outcome_list = [record.cash for record in records if record.balance_type == '支出'] income = sum(income_list) if len(income_list)!=0 else 0 outcome = sum(outcome_list) if len(outcome_list)!=0 else 0 net = income - outcome return render(request,'app/index.html',locals()) def settings(request): categories = Category.objects.filter() return render(request,'app/settings.html',locals()) def addCategory(request): if request.method == 'POST': posted_data = request.POST category = posted_data['add_category_name'] Category.objects.get_or_create(category=category) return redirect('/settings') def deleteCategory(request,category): Category.objects.filter(category=category).delete() return redirect('/settings') ``` ![](https://i.imgur.com/Ma8r36A.png) # 補充:跳出月曆,選擇日期 > jQuery CDN:https://code.jquery.com/ > * 複製 minified 並貼到 ==base.html== 下方: > bootstrap datepicker cdn:https://cdnjs.com/libraries/bootstrap-datepicker > * 複製 ```https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.8.0/js/bootstrap-datepicker.min.js``` 並貼到 base.html 下方 > > ```html= > ... > {% block content %} {% endblock %} > <!-- Bootstrap core JavaScript ================================================== --> > <script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script> > <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.8.0/js/bootstrap-datepicker.min.js"></script> > <script> > $(function(){ > $('#datepicker1').datepicker({ > format:'yyyy-mm-dd' > }); > }) > </script> > </body> > </html> > ``` > > ==forms.py== > ```python= > from django.forms import ModelForm, TextInput > from datetime import date > from .models import Record > > class RecordForm(ModelForm): > class Meta: > model = Record > fields = ['date','description','category','cash','balance_type'] > widgets = { > 'date':TextInput( > attrs = { > 'id':'datepicker1', > 'value':date.today().strftime('%Y-%m-%d') > } > ) > } > ``` ## ==views.py== ```python= from django.shortcuts import render, HttpResponse, redirect from .models import Record, Category from .forms import RecordForm # Create your views here. def hello(request): return render(request,'app/example_hello.html',{}) def frontpage(request): record_form = RecordForm(initial={'balance_type':'支出'}) records = Record.objects.filter() income_list = [record.cash for record in records if record.balance_type == '收入'] outcome_list = [record.cash for record in records if record.balance_type == '支出'] income = sum(income_list) if len(income_list)!=0 else 0 outcome = sum(outcome_list) if len(outcome_list)!=0 else 0 net = income - outcome return render(request,'app/index.html',locals()) def settings(request): categories = Category.objects.filter() return render(request,'app/settings.html',locals()) def addCategory(request): if request.method == 'POST': posted_data = request.POST category = posted_data['add_category_name'] Category.objects.get_or_create(category=category) return redirect('/settings') def deleteCategory(request,category): Category.objects.filter(category=category).delete() return redirect('/settings') def addRecord(request): if request.method == 'POST': form = RecordForm(request.POST) if form.is_valid(): form.save() return redirect('/') def deleteRecord(request): if request.method == 'POST': id = request.POST['delete_val'] Record.objects.filter(id=id).delete() return redirect('/') ``` ## ==index.html== ```htmlmixed= {% extends 'app/base.html' %} {% block content %} <div class="container-fluid"> <div class="row"> <nav class="col-md-2 d-none d-md-block bg-light sidebar"> <div class="sidebar-sticky"> <ul class="nav flex-column"> <li class="nav-item"> <a class="nav-link active" href="/"> <span data-feather="home"></span> 帳務總覽<span class="sr-only">(current)</span> </a> </li> <li class="nav-item"> <a class="nav-link" href="/settings"> <span data-feather="file"></span> 設定 </a> </li> </ul> </div> </nav> <main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-4"> <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"> <h1 class="page-header">帳務總覽</h1> </div> <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> <div class="row placeholders"> <div class="col-xs-8 col-sm-4 placeholder"> <h3>收入</h3> <span class="text-muted"><h2>{{ income }}</h2></span> </div> <div class="col-xs-8 col-sm-4 placeholder"> <h3>支出</h3> <span class="text-muted"><h2><font color="#DF565C">{{ outcome }}</font></h2></span> </div> <div class="col-xs-8 col-sm-4 placeholder"> <h3>存款</h3> <span class="text-muted"><h2><font color="#53DF7D">{{ net }}</font></h2></span> </div> </div> </div> </main> <main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-4"> <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"> <h2 class="sub-header">新增紀錄</h3> </div> <div class="table-responsive"> <form action="/add_record" method="post"> {% csrf_token %} <table class="table table-striped"> <col style="width:15%"> <col style="width:35%"> <col style="width:20%"> <col style="width:18%"> <col style="width:7%"> <thead> <tr> <th>日期</th> <th>描述</th> <th>分類</th> <th>金額</th> <th>收支</th> </tr> </thead> <tbody> <tr> {% for field in record_form %} <td>{{ field }}</td> {% endfor %} </tr> </tbody> </table> <div class="right-area"> <input type="submit" class="btn show-new-item" value="新增紀錄" /> </div> </form> </div> </main> <main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-4"> <h2 class="sub-header">歷史記錄</h2> <div class="table-responsive"> <table class="table table-striped table-sm"> <col style="width:18%"> <col style="width:27%"> <col style="width:20%"> <col style="width:18%"> <col style="width:7%"> <col style="width:5%"> <thead> <tr> <th>日期</th> <th>描述</th> <th>分類</th> <th>金額</th> <th>收/支</th> <th></th> </tr> </thead> <tbody> {% for record in records %} <tr> <td>{{ record.date | date:"Y-m-d"}}</td> <td>{{ record.description }}</td> <td>{{ record.category }}</td> <td>{{ record.cash }}</td> <td>{{ record.balance_type }}</td> <td> <form method="post" action="/delete_record"> {% csrf_token %} <input type="hidden" value="{{ record.id }}" name="delete_val"> <input type="submit" class="btn" value="刪除" /> </form> </td> </tr> {% endfor %} </tbody> </table> </div> </main> </div> </div> {% endblock %} ``` ## myproject_test 底下的 ==urls.py== ```python= from django.conf.urls import url from . import views urlpatterns = [ url(r'^$', views.frontpage), url(r'^settings$', views.settings), url(r'^add_category$', views.addCategory), url(r'^delete_category/(?P<category>\w+)',views.deleteCategory), url(r'^add_record$', views.addRecord), url(r'^delete_record$', views.deleteRecord), ] ``` # Step8:使用者登入與登出 ![](https://i.imgur.com/0L6oQvA.png) ![](https://i.imgur.com/Ip8Fgn5.png) ![](https://i.imgur.com/5VaikbM.png) ![](https://i.imgur.com/sxxX48F.png) ## ==views.py== ```python= from django.shortcuts import render, HttpResponse, redirect from .models import Record, Category from .forms import RecordForm from django.contrib.auth.decorators import login_required # Create your views here. @login_required def hello(request): return render(request,'app/example_hello.html',{}) @login_required def frontpage(request): record_form = RecordForm(initial={'balance_type':'支出'}) records = Record.objects.filter() income_list = [record.cash for record in records if record.balance_type == '收入'] outcome_list = [record.cash for record in records if record.balance_type == '支出'] income = sum(income_list) if len(income_list)!=0 else 0 outcome = sum(outcome_list) if len(outcome_list)!=0 else 0 net = income - outcome return render(request,'app/index.html',locals()) @login_required def settings(request): categories = Category.objects.filter() return render(request,'app/settings.html',locals()) @login_required def addCategory(request): if request.method == 'POST': posted_data = request.POST category = posted_data['add_category_name'] Category.objects.get_or_create(category=category) return redirect('/settings') @login_required def deleteCategory(request,category): Category.objects.filter(category=category).delete() return redirect('/settings') @login_required def addRecord(request): if request.method == 'POST': form = RecordForm(request.POST) if form.is_valid(): form.save() return redirect('/') @login_required def deleteRecord(request): if request.method == 'POST': id = request.POST['delete_val'] Record.objects.filter(id=id).delete() return redirect('/') ``` ## ==myproject_test 中的 urls.py== ```python= """project_chia URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/1.9/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.conf.urls import url, include 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) """ from django.conf.urls import url, include from django.contrib import admin from django.contrib.auth import views as auth_views from . import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^', include('chia_app.urls')), url(r'^accounts/login', auth_views.login), url(r'^accounts/logout', views.logout), ] ``` ## 新增 registration 資料夾,並放入 ==login.html== ``` (py3env) testchia@fengchia-swift-sf314-52:~/myproject_test$ cd chia_app (py3env) testchia@fengchia-swift-sf314-52:~/myproject_test/chia_app$ ls admin.py forms.py migrations __pycache__ templates urls.py apps.py __init__.py models.py static tests.py views.py (py3env) testchia@fengchia-swift-sf314-52:~/myproject_test/chia_app$ cd templates (py3env) testchia@fengchia-swift-sf314-52:~/myproject_test/chia_app/templates$ ls app (py3env) testchia@fengchia-swift-sf314-52:~/myproject_test/chia_app/templates$ mkdir registration ``` ### ==login.html== ```htmlmixed= {% load staticfiles %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>accounts demo</title> <!-- Bootstrap core CSS --> <link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet"> <!-- Custom styles for this template --> <link href="{% static 'css/dashboard.css' %}" rel="stylesheet"> <style> td { padding: 5px } </style> </head> <body> <nav class="navbar-dark bg-dark shadow fixed-top"> <center><h1 class="navbar-brand col-sm-9">My 帳本</h1></center> </nav> {% if form.errors %} <p>您的帳號或密碼有誤。</p> {% endif %} {% if next %} {% if user.is_authenticated %} <p>您沒有權限造訪此網頁。</p> {% else %} <p>請先登入。</p> {% endif %} {% endif %} <form method="post" action="/accounts/login"> {% csrf_token %} <table align="center" style="margin-top:100px"> <tr> <td>{{ form.username.label_tag }}</td> <td>{{ form.username }}</td> </tr> <tr> <td>{{ form.password.label_tag }}</td> <td>{{ form.password }}</td> </tr> <tr> <!--我是next:{{ next }}--> </tr> <tr> <td></td> <td> <input type="submit" value="login" class="btn small-button" /> </td> </tr> </table> <input type="hidden" name="next" value="{{ next }}" /> </form> </body> </html> ``` ## myproject_test 底下新增 ==views.py== ```python= from django.contrib import auth from django.shortcuts import redirect def logout(request): auth.logout(request) return redirect('/') ``` # Step9:挑戰關卡-使用者專屬內容 ![](https://i.imgur.com/H1c3ODT.png) * 影片:https://drive.google.com/file/d/19LFP_btgpI9KpLA4wOZszbFe81BYRP3K/view # Step10:[上傳專案到github](https://drive.google.com/open?id=1OMARgIYtAC5owiHQMKTC_yGFUYuRgbhW)、[部署專案至Python anywhere](https://drive.google.com/open?id=1gbJJxQj0yRJ9J9I693SBQAs3euM3tfNJ)

Import from clipboard

Paste your markdown or webpage here...

Advanced permission required

Your current role can only read. Ask the system administrator to acquire write and comment permission.

This team is disabled

Sorry, this team is disabled. You can't edit this note.

This note is locked

Sorry, only owner can edit this note.

Reach the limit

Sorry, you've reached the max length this note can be.
Please reduce the content or divide it to more notes, thank you!

Import from Gist

Import from Snippet

or

Export to Snippet

Are you sure?

Do you really want to delete this note?
All users will lose their connection.

Create a note from template

Create a note from template

Oops...
This template has been removed or transferred.
Upgrade
All
  • All
  • Team
No template.

Create a template

Upgrade

Delete template

Do you really want to delete this template?
Turn this template into a regular note and keep its content, versions, and comments.

This page need refresh

You have an incompatible client version.
Refresh to update.
New version available!
See releases notes here
Refresh to enjoy new features.
Your user state has changed.
Refresh to load new user state.

Sign in

Forgot password

or

By clicking below, you agree to our terms of service.

Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
Wallet ( )
Connect another wallet

New to HackMD? Sign up

Help

  • English
  • 中文
  • Français
  • Deutsch
  • 日本語
  • Español
  • Català
  • Ελληνικά
  • Português
  • italiano
  • Türkçe
  • Русский
  • Nederlands
  • hrvatski jezik
  • język polski
  • Українська
  • हिन्दी
  • svenska
  • Esperanto
  • dansk

Documents

Help & Tutorial

How to use Book mode

Slide Example

API Docs

Edit in VSCode

Install browser extension

Contacts

Feedback

Discord

Send us email

Resources

Releases

Pricing

Blog

Policy

Terms

Privacy

Cheatsheet

Syntax Example Reference
# Header Header 基本排版
- Unordered List
  • Unordered List
1. Ordered List
  1. Ordered List
- [ ] Todo List
  • Todo List
> Blockquote
Blockquote
**Bold font** Bold font
*Italics font* Italics font
~~Strikethrough~~ Strikethrough
19^th^ 19th
H~2~O H2O
++Inserted text++ Inserted text
==Marked text== Marked text
[link text](https:// "title") Link
![image alt](https:// "title") Image
`Code` Code 在筆記中貼入程式碼
```javascript
var i = 0;
```
var i = 0;
:smile: :smile: Emoji list
{%youtube youtube_id %} Externals
$L^aT_eX$ LaTeX
:::info
This is a alert area.
:::

This is a alert area.

Versions and GitHub Sync
Get Full History Access

  • Edit version name
  • Delete

revision author avatar     named on  

More Less

Note content is identical to the latest version.
Compare
    Choose a version
    No search result
    Version not found
Sign in to link this note to GitHub
Learn more
This note is not linked with GitHub
 

Feedback

Submission failed, please try again

Thanks for your support.

On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

Please give us some advice and help us improve HackMD.

 

Thanks for your feedback

Remove version name

Do you want to remove this version name and description?

Transfer ownership

Transfer to
    Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

      Link with GitHub

      Please authorize HackMD on GitHub
      • Please sign in to GitHub and install the HackMD app on your GitHub repo.
      • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
      Learn more  Sign in to GitHub

      Push the note to GitHub Push to GitHub Pull a file from GitHub

        Authorize again
       

      Choose which file to push to

      Select repo
      Refresh Authorize more repos
      Select branch
      Select file
      Select branch
      Choose version(s) to push
      • Save a new version and push
      • Choose from existing versions
      Include title and tags
      Available push count

      Pull from GitHub

       
      File from GitHub
      File from HackMD

      GitHub Link Settings

      File linked

      Linked by
      File path
      Last synced branch
      Available push count

      Danger Zone

      Unlink
      You will no longer receive notification when GitHub file changes after unlink.

      Syncing

      Push failed

      Push successfully