├── .gitignore ├── template ├── img │ └── now.png └── README.md ├── project ├── img │ └── it_works.png └── README.md ├── book.json ├── README.md ├── package.json ├── SUMMARY.md ├── .travis.yml ├── intro └── README.md ├── remark └── README.md ├── third_party_app └── README.md ├── Gruntfile.js ├── LICENSE ├── apps └── README.md ├── deploy_to_cloud └── README.md ├── admin └── README.md ├── views_and_urls └── README.md ├── installation └── README.md ├── forms └── README.md ├── views_revisited └── README.md └── models └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .grunt 3 | /_book/ 4 | *.sublime-project 5 | *.sublime-workspace 6 | -------------------------------------------------------------------------------- /template/img/now.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daikeren/django_tutorial/HEAD/template/img/now.png -------------------------------------------------------------------------------- /project/img/it_works.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daikeren/django_tutorial/HEAD/project/img/it_works.png -------------------------------------------------------------------------------- /book.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["ga"], 3 | "pluginsConfig": { 4 | "ga": { 5 | "token": "UA-312079-14" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Django Tutorial 2 | 3 | 這是為 [PyCon APAC 2014](https://tw.pycon.org/2014apac/) 所開的 Django Tutorial 課程教材,目前更新到最新的 Django 2.0 + Python 3。 4 | 5 | 本課程中,將會以建立一個部落格為例子,給大家對於 Django 的重要元件能夠有基本的認知,在課程結束之後,學員將可以有用 Django 架起簡單網站的能力。 6 | 7 | 這份教材是用 [gitbook](http://www.gitbook.io/) 編寫而成,如果有任何問題或是建議,歡迎發 issue 過來,希望大家可以一起幫忙,讓這份教材更為完善。 8 | 9 | Build 好的版本會放在 [http://daikeren.github.io/django_tutorial/](http://daikeren.github.io/django_tutorial/),歡迎大家直接取用 :) 10 | 11 | 最終完成的程式碼放在 [https://github.com/daikeren/blog](https://github.com/daikeren/blog) 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "django_tutorial", 3 | "version": "0.2.1", 4 | "description": "", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/daikeren/django_tutorial.git" 8 | }, 9 | "author": "Andy Dai ", 10 | "license": "Apache 2", 11 | "dependencies": {}, 12 | "devDependencies": { 13 | "grunt": "~0.4.1", 14 | "grunt-gitbook": "~0.5.2", 15 | "grunt-gh-pages": "~0.9.1", 16 | "grunt-contrib-clean": "~0.5.0", 17 | "gitbook-plugin-ga": "~0.1.0" 18 | }, 19 | "peerDependencies": { 20 | "grunt": "~0.4.1" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | * [Django 簡介](intro/README.md) 4 | * [安裝 Django](installation/README.md) 5 | * [Django Project](project/README.md) 6 | * [Django APPs](apps/README.md) 7 | * [Django Views & Django URLs](views_and_urls/README.md) 8 | * [Django Template](template/README.md) 9 | * [Django 與資料庫的互動 - Django Model](models/README.md) 10 | * [Django 最吸引人的 feature 之一 - Django Admin](admin/README.md) 11 | * [Django Views, Django URL & Django Template 再訪](views_revisited/README.md) 12 | * [Django Forms & Django Views 的結合](forms/README.md) 13 | * [Django 的第三方套件們](third_party_app/README.md) 14 | * [把你的 Django Project 丟上雲端](deploy_to_cloud/README.md) 15 | * [這只是開始...](remark/README.md) 16 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" 4 | before_script: 5 | - git config --global user.name "Travis CI" 6 | - git config --global user.email "andy@dorm7.com" 7 | 8 | before_install: npm install -g grunt-cli 9 | install: 10 | - "npm install" 11 | after_success: 12 | - git config credential.helper "store --file=.git/credentials" 13 | - echo "https://${GH_TOKEN}:@github.com" > .git/credentials 14 | - "grunt gitbook" 15 | - "grunt gh-pages:travis" 16 | env: 17 | global: 18 | - secure: "XyXGLCsPNUuaoHvKSOJqEHnbkmHtFn7O/g0hsNaPISb82dY4gINCr4HTrIQKHZ+Vti54F/P3XEY6rwhGcD6keyUTf8enZ9gSlbLX9Xwc4+wv6qaW1uI9exxMBdGs9kv7mCK0Z3FQEWksThw3ezpWD/JS+lmJ+dAkNWc3A55tkyM=" -------------------------------------------------------------------------------- /intro/README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | 在 Python 的世界當中有[許多的 Web Framework](https://wiki.python.org/moin/WebFrameworks),在眾多的 Web Framework 當中, 4 | 最常被提到的就是 [Django](https://www.djangoproject.com/) 了。 5 | 6 | 雖然在台灣,Django 的知名度比不上 [Ruby on Rails](http://rubyonrails.org/),但是在國外,Django 可是許多網站背後的支柱。像是 [Pinterest](http://www.pinterest.com/)、 7 | [Instgram](http://instagram.com/)、[Disqus](http://disqus.com/)、[Mozilla Developer Network](https://developer.mozilla.org/) 等等。 8 | 9 | 和其他比較輕量級的 Python Web Framework (如 [bottle](http://bottlepy.org/)、[Flask](http://flask.pocoo.org)) 相比,使用 Django 最大的好處就是包括資料庫的連接、表單、登入系統、管理界面等等建構網站應該要有的元件都是 Django 本身的一部份,雖然乍看之下失去了一些彈性,但是卻可以讓你再建構網站的時候可以更快更有效率! 10 | 11 | 接下來就讓我們一起來進入 Django 的世界吧! 12 | -------------------------------------------------------------------------------- /remark/README.md: -------------------------------------------------------------------------------- 1 | # 這只是開始... 2 | 3 | 恭喜你看到了這邊,你已經對 Django 有了最基本的認知,如果你想要更精進的話,或許可以從想想可以幫這個 blog project 加些什麼東西。下面是我想的一些功能: 4 | 5 | * 目前只有類別,是不是可以加入標籤 (tag) 呢? 6 | * 除了新增之外,是不是也能夠有個頁面能對已經存在的 article 做修改? 7 | * 我們好像都沒有作者的概念,是不是可以有作者呢?登入要怎麼處理? 8 | * rss 怎麼生? 9 | * CSS/JavaScript 該放在哪裡? 10 | * 如果 Model 的欄位要新增/刪除該怎麼辦? 11 | * 怎麼上傳圖片啊? 12 | 13 | 這些功能做完之後,我相信你會對 Django 有更深一層的了解。 14 | 15 | 另外也可以看看以下的參考資料: 16 | 17 | * [Django 官方文件](https://www.djangoproject.com/) - 必看!文件相當詳細,不過建議有問題再來找。 18 | * [Django Book](http://www.djangobook.com/en/2.0/index.html) - 雖然書的內容有點舊,不過還是有些東西值得參考 19 | * [Getting Started with Django](http://gettingstartedwithdjango.com/) - 如果你比較喜歡看 video,或許可以參考這個網站 20 | * [Two Scoops of Django](http://www.amazon.com/Two-Scoops-Django-Best-Practices/dp/098146730X) - 近期寫的最好的 Django 書之一,有看一定有收獲 21 | 22 | 除此之外,也歡迎大家可以來 [Taipei.py](http://www.meetup.com/Taipei-py/) 的活動跟大家進行一些實體的交流,彼此之間多聊聊才更能夠有進步 :) 23 | -------------------------------------------------------------------------------- /project/README.md: -------------------------------------------------------------------------------- 1 | # Django Project 2 | 3 | 接下來讓我們開始第一個 Django Project 吧! 4 | 5 | 建立 Django Project 很簡單,只要輸入 6 | 7 | ``` 8 | pipenv run django-admin startproject blog 9 | ``` 10 | 11 | 就可以看到我們的資料夾多了一個叫做 blog 的目錄,這個目錄當中的檔案如下: 12 | 13 | ``` 14 | . 15 | ├── Pipfile 16 | ├── Pipfile.lock 17 | └── blog 18 | ├── blog 19 | │   ├── __init__.py 20 | │   ├── settings.py 21 | │   ├── urls.py 22 | │   └── wsgi.py 23 | └── manage.py 24 | ``` 25 | 26 | 在這個階段我們只要注意 manage.py 這個檔案就好。manage.py 是一個 Django 的命令列工具,在 Django 當中許多的工作都必須要透過 manage.py 來完成。接下來我們將執行第一個用 manage.py 的工作,也是開發 Django 中可能是最常跑的指令 - runserver。runserver 的目的是讓 Django 啟動一個簡單用的 web server,讓我們可以很容易的做開發。 27 | 28 | 首先先切到 blog 資料夾 29 | 30 | ``` 31 | cd blog 32 | ``` 33 | 34 | 接著輸入 35 | 36 | ``` 37 | pipenv run python manage.py runserver 38 | ``` 39 | 40 | 打開你的瀏覽器,在網址的部分輸入 http://localhost:8000/ ,應該會看到一個如下圖的頁面,這就代表你已經成功地創建了你的第一個 Django Project。 41 | 42 | ![It Works](img/it_works.png) 43 | -------------------------------------------------------------------------------- /third_party_app/README.md: -------------------------------------------------------------------------------- 1 | # Django 的第三方套件們 2 | 3 | 不知道到這邊為止大家有沒有體會到 Django 強大的威力?目前為止我們都只是用 Django 本身自帶的功能,但是 Django 除了自己本身有完整的功能外,還有許多的第三方套件可以使用。目前大多的第三方套件都能夠在 [Django Packages](https://www.djangopackages.com/) 尋找到。 4 | 5 | 讓我們來裝個套件玩玩吧!前面看過了 Django Admin 的畫面,我想有些人會覺得配色、版面看起來都太古老,希望可以漂亮一點。在這邊,我們來用 [django-grappelli](https://django-grappelli.readthedocs.io/en/latest/) 來強化 Django Admin! 6 | 7 | 首先,切換到你的 shell,輸入 8 | 9 | ```pipenv install django-grappelli``` 10 | 11 | 接著,在 blog/settings.py 當中修改 INSTALLED_APPS,加入 grappelli 進去,記得要放在 django.contrib.admin 之前。 12 | 13 | ```python 14 | INSTALLED_APPS = [ 15 | ... 16 | 'grappelli', 17 | 'django.contrib.admin', 18 | ... 19 | ] 20 | ``` 21 | 22 | 最後,在 blog/urls.py 當中加上對應的 URL 23 | 24 | ```python 25 | urlpatterns = [ 26 | ... 27 | path('grappelli/', include('grappelli.urls')), # grappelli URLS 28 | ... 29 | ] 30 | ``` 31 | 32 | 打開 http://localhost:8000/admin ,看看 Django Admin 是不是長的不太一樣了呢? 33 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | var path = require("path"); 2 | 3 | module.exports = function (grunt) { 4 | grunt.loadNpmTasks('grunt-gitbook'); 5 | grunt.loadNpmTasks('grunt-gh-pages'); 6 | grunt.loadNpmTasks('grunt-contrib-clean'); 7 | 8 | grunt.initConfig({ 9 | 'gitbook': { 10 | development: { 11 | input: "./", 12 | github: "daikeren/django_tutorial" 13 | } 14 | }, 15 | 'gh-pages': { 16 | travis: { 17 | options: { 18 | repo: 'https://' + process.env.GH_TOKEN + '@github.com/daikeren/django_tutorial.git', 19 | silent: true, 20 | base: '_book' 21 | }, 22 | src: ['**'] 23 | }, 24 | }, 25 | 'clean': { 26 | files: '.grunt' 27 | } 28 | }); 29 | 30 | grunt.registerTask('publish', [ 31 | 'gitbook', 32 | 'gh-pages', 33 | 'clean' 34 | ]); 35 | grunt.registerTask('default', 'gitbook'); 36 | }; 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Andy Dai 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /apps/README.md: -------------------------------------------------------------------------------- 1 | # Django APPs 2 | 3 | 接下來讓我們來正式開始寫我們的 Django Project 吧!Django Project 是由一個個的 Django APP 所組成,對於剛學習 Django 的人來說,可能會不知道所謂的 Django APP 是什麼。其實一個 Django APP 很簡單,一般來說我們會希望一個 Django APP 能夠 "do one thing and do it well." 也就是說盡可能的讓功能單純,這樣子不管是在測試或是管理方面可以更方便一些。 4 | 5 | 舉個例子來說,如果你要建立一個網路購物網站,那麼可能會有以下的 app 6 | 7 | * account: 管理使用者帳號 8 | * product: 管理商品 9 | * order: 管理訂單 10 | * shipping: 管理物流 11 | 12 | ## 第一個 Django APP 13 | 14 | 還記得剛剛的 manage.py 嗎?在這邊我們也會用 manage.py 來創建我們的第一個 Django APP。要創建 Django APP,首先,我們先來創建一個管理文章的 Django APP,我們叫做 article 好了。在 shell 底下輸入: 15 | 16 | ``` 17 | pipenv run python manage.py startapp article 18 | ``` 19 | 20 | 我們可以看到建立起了一個叫做 article 的目錄,在 article 這個目錄底下我們會看到以下的檔案: 21 | 22 | ``` 23 | . 24 | ├── __init__.py 25 | ├── admin.py 26 | ├── apps.py 27 | ├── migrations 28 | │   └── __init__.py 29 | ├── models.py 30 | ├── tests.py 31 | └── views.py 32 | ``` 33 | 34 | 這樣就順利的建立起我們第一個 app 的目錄。在接下來的章節我們會來看看其中的檔案,不過現在我們暫時不管他。 35 | 36 | 接著我們要讓 Django 知道我們有了 article 這個 APP,讓我們打開 blog 資料夾中 settings.py 這個檔案。這個檔案顧名思義就是管理所有跟 Django 相關的設定。找到 settings.py 當中的 INSTALLED_APPS 這個變數,在最下面加上 'article' 就成功的讓 Django 知道會有一個叫做 article 的 APP。 37 | 38 | ```python 39 | INSTALLED_APPS = [ 40 | 'django.contrib.admin', 41 | 'django.contrib.auth', 42 | 'django.contrib.contenttypes', 43 | 'django.contrib.sessions', 44 | 'django.contrib.messages', 45 | 'django.contrib.staticfiles', 46 | 'article', 47 | ] 48 | ``` 49 | -------------------------------------------------------------------------------- /deploy_to_cloud/README.md: -------------------------------------------------------------------------------- 1 | # 把你的 Django Project 丟上雲端 2 | 3 | 好不容易做了網站,接下來讓我們把我們的網站丟上去讓大家看看。在這邊,我們使用最常見的 [Heroku](https://www.heroku.com/) 來當作我們的 hosting。Heroku 免費的額度基本上拿來做些小的網站應該是夠用。以下假設你都已經註冊好了 heroku 的帳號了。接下來讓我們開始把我們的 Project 丟上去。 4 | 5 | 首先,我們先輸入 6 | 7 | ```shell 8 | heroku login 9 | ``` 10 | 11 | terimnal 會出現要輸入你所註冊的帳號以及密碼 12 | 13 | 爲了讓程式可以更方便的 deploy 到 heroku 上面,我們要安裝 `django-heroku` 這個 package,它會幫助我們完成一些相關的設定 14 | 15 | ```shell 16 | pipenv install django-heroku 17 | ``` 18 | 19 | 接着,我們在 blog/settings.py 最底下加上以下兩行 20 | 21 | ```python 22 | import django_heroku 23 | django_heroku.settings(locals()) 24 | ``` 25 | 26 | 接着,在 blog 目錄底下新增一個 Procfile,內容如下 27 | 28 | ```shell 29 | web: gunicorn blog.wsgi 30 | ``` 31 | 32 | 接着,我們要初始化 git repository 33 | 34 | ```shell 35 | git init 36 | ``` 37 | 38 | 把檔案加到 git repository 當中 39 | 40 | ```shell 41 | git add . 42 | git commit -m "First Commit" 43 | ``` 44 | 45 | 創建 heroku app 46 | 47 | ```shell 48 | heroku create 49 | ``` 50 | 51 | 把你的 code 推到 heroku 上面 52 | 53 | ```shell 54 | git push heroku master 55 | ``` 56 | 57 | 創建資料庫 58 | 59 | ```shell 60 | heroku run python manage.my migrate 61 | ``` 62 | 63 | 開啓你的網站 64 | 65 | ```shell 66 | heroku open 67 | ``` 68 | 69 | 你會看到類似 `https://agile-waters-53872.herokuapp.com/` 這樣的 url,上面跟你的網站一樣,不過沒有資料。這是因爲你在 local 開發的時候使用的資料庫跟遠端不同,你可以連到 `/create/` 這個 url 創建你的文章。 70 | 71 | 好了,現在你已經把你的網站丟上去了。如果之後你有加任何功能,只要記得用 `git commit` 以及 `git push heroku master` 就可以更新。 72 | -------------------------------------------------------------------------------- /admin/README.md: -------------------------------------------------------------------------------- 1 | # Django 最吸引人的 feature 之一 - Django Admin 2 | 3 | 上一個章節我們了解到 Django Model 要怎麼建置,也透過了 Django Shell 來對 Model 做操作,但是常常我們會希望能夠直接有個方便的網頁界面可能對這些 Model 做創造、讀取、更新、刪除的動作,那麼該怎麼辦呢?許多的 web framework 可能都需要手動刻一個這樣的界面,但是 Django 當中有 admin 這個套件來幫你很容易地完成相關的事情。 4 | 5 | 看看在 settings.py 當中的 INSTALLED_APPS 當中已經裝了 'django.contrib.admin' 這個 app 6 | 7 | ```python 8 | INSTALLED_APPS = ( 9 | ... 10 | # Uncomment the next line to enable the admin: 11 | 'django.contrib.admin', 12 | ... 13 | ) 14 | ``` 15 | 16 | 接著來看看 blog/urls.py 當中 17 | 18 | ```python 19 | from django.contrib import admin 20 | 21 | 22 | urlpatterns = [ 23 | ... 24 | path('admin/', admin.site.urls), 25 | ... 26 | ] 27 | ``` 28 | 29 | 30 | 接著造訪 http://localhost:8000/admin ,你會發現需要輸入帳號以及密碼。這時候在 termminal 底下輸入 31 | 32 | ```shell 33 | pipenv run python ./manage.py createsuperuser 34 | ``` 35 | 36 | 創建一個 superuser,創好之後在 admin 界面輸入帳號以及密碼可以登入。如果一切順利的話你會看到 Django Admin 的畫面。不過這個時候 Django Admin 還看不到我們建立的 Category, Article 這兩個 Model,所以我們要告訴 Django Admin 這件事情。 37 | 38 | 在 article 目錄底下,新增 admin.py,內容如下: 39 | 40 | ```python 41 | from django.contrib import admin 42 | from article.models import Article, Category 43 | 44 | admin.site.register(Article) 45 | admin.site.register(Category) 46 | ``` 47 | 48 | 這時候重新 reload http://localhost:8000/admin,應該就會看到上面出現 Article 跟 Category 的 admin 界面,我們就可以在這邊做創造、讀取、更新、刪除的動作了。 49 | 50 | 51 | ## 練習 52 | 53 | * 玩玩看 Django Admin 吧,隨意新增幾個 Article 或是 Category 看看 54 | -------------------------------------------------------------------------------- /template/README.md: -------------------------------------------------------------------------------- 1 | # Django Template 2 | 3 | 在前一章當中我們透過在 view 當中使用直接輸出字串的方式來幫助我們輸出 HTML,不過這樣會有一個很大的壞處:通常來說 HTML 的部分可能是由前端工程師寫的,如果我們把 HTML 寫在 view 當中,會造成維護以及修改上面的困難,因此 Django 提供了 Django Template 來幫助我們解決這部分的問題。 4 | 5 | ## 第一個 Template 6 | 7 | 讓我們在我們的 article 目錄底下建立一個 templates 目錄。裡面新增一個 now.html 檔案,內容如下 8 | 9 | ```html 10 | 11 | 12 | 13 | 14 | This is an example template 15 | 16 | 17 | 18 |

{{ now }}

19 | 20 | 21 | ``` 22 | 23 | 在這邊,我們發現有個特別的 24 | 25 | ```html 26 |

{{ now }}

27 | ``` 28 | 29 | 的部分,這邊用 `{{ now }}` 代表的是這部分會由從 django view 當中傳入的 `now` 來做變數的代換 30 | 31 | 接著,打開我們之前寫的 article/views.py,把之前寫的 now view 改成: 32 | 33 | ```python 34 | from django.shortcuts import render 35 | 36 | def now(request): 37 | return render(request, "now.html", {'now': datetime.now()}) 38 | ``` 39 | 40 | 41 | 我們 import 了 [django.shortcuts.render](https://docs.djangoproject.com/en/2.0/topics/http/shortcuts/#render),這個 function 可以幫助我們讀取 template 之後,把變數以 python dictionary 的方式傳入 template 當中,最後再 render 出來並且回傳到瀏覽器中。打開 http://localhost:8000/now 看看,如果都沒做錯的話應該會出現類似以下的畫面。 42 | 43 | ![now](img/now.png) 44 | 45 | 在這邊大家可能會覺得好像 Django Template 也沒做什麼事情,只是個簡單的變數取代而已。不過其實 Django Template 提供了很多[內建的 template tag 跟 template filter](https://docs.djangoproject.com/en/2.0/ref/templates/builtins/),也提供了你可以擴充 Django Template 的功能。 46 | 47 | 比如說我們這邊希望修改一下 `{{ now }}` 所輸出的格式,原本是的 `May 17, 2018, 7:22am` 的格式想改成 `Thu 17 May 2018` 這種樣子,我們可以把原本的 `{{ now }}` 改成 `{{ now|date:"D d M Y" }}`。這邊我們使用了 `[date](https://docs.djangoproject.com/en/2.0/ref/templates/builtins/#date)` 這個 template tag,你也可以參考說明改成你想要的形式。 48 | 49 | 這邊我們很簡單的寫了第一個 template,也用了一個 template tag,在後面我們會更詳細的介紹其他的 template 應用。 50 | -------------------------------------------------------------------------------- /views_and_urls/README.md: -------------------------------------------------------------------------------- 1 | # Django Views & Django URLs 2 | 3 | 到這裡大家應該會在想 "搞了半天都在弄這些有的沒的,什麼時候才能開始做我們第一個頁面呢?" 這個章節會讓我們創立第一個頁面,並且讓我們了解到 Django 很重要的兩個部分 - URL 跟 Views. 4 | 5 | ## Django Views 6 | 7 | 一個網頁程式當中的邏輯通常是這個樣子的:request 進來 -> 從資料庫撈資料 -> 處理資料 -> 把網頁呈現出來。由於現在我們還沒有講到要怎麼樣做跟資料庫之間的互動,所以我們先來講講從 request 進來到頁面呈現出來這段過程 Django 是怎麼做的。 8 | 9 | 在 Django 當中,處理這部分的邏輯稱之為 Django Views,通常我們都會放在 Django APP 當中的 views.py 檔案裡面。讓我們來寫第一個 Django View 吧!如同所有程式剛開始一樣,我們先從 Hello World 開始! 10 | 11 | 在 article/views.py 底下新增以下的程式碼: 12 | 13 | ```python 14 | from django.http import HttpResponse 15 | 16 | def home(request): 17 | s = "Hello World!" 18 | return HttpResponse(s) 19 | ``` 20 | 21 | 這是一個最簡單的 Django View,我們可以看到一個 Django View 基本上就是一個 python function,傳入值是 request,它的型別是 [HttpRequest](https://docs.djangoproject.com/en/2.0/ref/request-response/#httprequest-objects),當中 Django 幫我們封裝了有關一個 HTTP Request 進來會傳入的資料。包含了 request body, request method... 等等,在往後的章節當中我們會看到這部分的應用。 22 | 23 | 然後回傳一個用 "Hello World!" 字串當 constructor 的 [HttpResponse](https://docs.djangoproject.com/en/2.0/ref/request-response/#httpresponse-objects) 物件。同樣的,HttpResponse 也幫我們封裝了回傳給 browser 的資訊。包含了 content type, status code 等等。 24 | 25 | 透過 Django 的 Request 還有 Response 物件,我們在處理複雜的 HTTP 的時候可以省下更多的麻煩事要處理,讓我們可以更專注在把東西做好上面。 26 | 27 | ## Django URLs 28 | 29 | 我們寫好第一個 view 之後,那麼我們該怎麼讓 Django 知道連到哪個 URL 會呼叫這個 view 呢?這就是 Django URLs 會處理的事情。讓我們打開 blog/urls.py 這個檔案,在 urlpatterns 當中加入以下的 code 30 | 31 | ```python 32 | from article.views import home 33 | 34 | urlpatterns = [ 35 | path('admin/', admin.site.urls), 36 | path('home', home), 37 | ] 38 | ``` 39 | 40 | 在這邊,我們可以看到我們使用了一個 [path function](https://docs.djangoproject.com/en/2.0/ref/urls/#path) ,這個 function 有兩個傳入值,第一個傳入值是 route,在此我們傳入一個空字串,也就是會對應到 url 當中沒有任何東西。而第二個傳入值是個 view function 的位置,這邊我們是傳入剛剛寫的 `article.views.home` 41 | 42 | 接著切換到你的 terminal,重新輸入 43 | 44 | ``` 45 | pipenv run python manage.py runserver 46 | ``` 47 | 48 | 打開你的瀏覽器,開啓 [http://localhost:8000/home](http://localhost:8000/home),應該就會看到 Hello World! 出現! 49 | 50 | ## 練習 51 | 52 | 現在你已經會寫一個簡單的 view 還有 url 了,來再新增一個 view function,讓我們連到 http://localhost:8000/now 的時候會輸出現在的時間吧! 53 | 54 | ## 解答 55 | 56 | 要達到目的,我們要做兩件事情 57 | 58 | 1. 新增一個顯示時間的 view function 59 | 60 | 打開 article/views.py 這個檔案 61 | 62 | ```python 63 | from datetime import datetime 64 | 65 | 66 | def now(request): 67 | return HttpResponse(datetime.now()) 68 | ``` 69 | 70 | 2. 把 /now 這個 url 跟上面的 view function 做連結 71 | 72 | 打開 blog/urls.py 73 | 74 | ```python 75 | from article.views import now 76 | 77 | urlpatterns = [ 78 | ... 79 | path('now', now), 80 | ... 81 | ] 82 | ``` 83 | -------------------------------------------------------------------------------- /installation/README.md: -------------------------------------------------------------------------------- 1 | # 安裝 Django 2 | 3 | 在開始之前,我們先在我們的根目錄下面建立一個我們工作的目錄。 4 | 5 | ``` 6 | mkdir django_tutorial 7 | ``` 8 | 9 | 切換到我們剛剛建立的目錄下 10 | 11 | ``` 12 | cd django_tutorial 13 | ``` 14 | 15 | ## 安裝與設定 Python 16 | 17 | 我們將會使用 Django 2.0 作爲教學的版本,Django 2.0 之後都只支援 Python3,如果要使用 Python2,請使用 Django 1.11。下面是不同 OS 安裝 Python3 的說明。 18 | 19 | ### MacOS 20 | 21 | 在 MacOS 底下請先安裝好 [HomeBrew](https://brew.sh/),安裝完成之後,輸入: 22 | 23 | `brew install python3` 24 | 25 | 接着,輸入 `python3`,如果出現類似以下的畫面就代表安裝完成 26 | 27 | ```shell 28 | Python 3.6.5 (default, Apr 25 2018, 14:23:58) 29 | [GCC 4.2.1 Compatible Apple LLVM 9.1.0 (clang-902.0.39.1)] on darwin 30 | Type "help", "copyright", "credits" or "license" for more information. 31 | >>> 32 | ``` 33 | 34 | ### Linux 35 | 36 | 我們這裏以 ubuntu 爲例,如果你是使用其他的 Linux distribution,請各自參考自己的套件管理。 37 | 38 | `sudo apt update -y && sudo apt install python3 python3-venv -y` 39 | 40 | 接着,輸入 `python3`,如果出現類似以下的畫面就代表安裝完成 41 | 42 | ```shell 43 | Python 3.6.5 (default, Apr 25 2018, 14:23:58) 44 | [GCC 4.2.1 Compatible Apple LLVM 9.1.0 (clang-902.0.39.1)] on darwin 45 | Type "help", "copyright", "credits" or "license" for more information. 46 | >>> 47 | ``` 48 | 49 | ### Windows 50 | 51 | 在 Windows 底下,請參考 [Python Releases for Windows](https://www.python.org/downloads/windows/),下載 Python 3.4 之後的版本安裝。 52 | 53 | 接着,輸入 `python3`,如果出現類似以下的畫面就代表安裝完成 54 | 55 | ```shell 56 | Python 3.6.5 (default, Apr 25 2018, 14:23:58) 57 | [GCC 4.2.1 Compatible Apple LLVM 9.1.0 (clang-902.0.39.1)] on darwin 58 | Type "help", "copyright", "credits" or "license" for more information. 59 | >>> 60 | ``` 61 | 62 | ## 安裝 pipenv 63 | 64 | 如果之前你有接觸過 python,你可能會聽過 virtualenv 這個拿來管理 Python 虛擬環境的套件。[Kenneth Reitz](https://github.com/kennethreitz) 開發的 [pipenv](https://github.com/pypa/pipenv) 讓我們可以更加方便的管理 Python 的開發環境。關於 pipenv 更詳細的介紹,可以看 pipenv 的[官網](https://docs.pipenv.org/)。 65 | 66 | 如果使用 MacOS,可以輸入底下的指令安裝 67 | 68 | ```shell 69 | brew install pipenv 70 | ``` 71 | 如果使用 ubuntu,可以輸入底下的指令安裝 72 | 73 | ```shell 74 | sudo apt install software-properties-common python-software-properties 75 | sudo add-apt-repository ppa:pypa/ppa 76 | sudo apt update 77 | sudo apt install pipenv 78 | ``` 79 | 80 | 或是你也可以直接透過 pip 安裝 81 | 82 | ```shell 83 | pip install pipenv 84 | ``` 85 | 86 | 如果輸入 `pipenv --version` 可以看到 87 | 88 | ```shell 89 | pipenv, version 9.0.0 90 | ``` 91 | 92 | 或是更高的版本,那麼就代表你裝好了 pipenv。 93 | 94 | ## Install Django 95 | 96 | 安裝 Django 十分簡單,只要透過 pip 就可以完成。在 terminal 底下輸入: 97 | 98 | ``` 99 | pipenv install django 100 | ``` 101 | 102 | 便會下載最新版的 django 並且完成安裝。 103 | 104 | 要確認 django 有沒有安裝好,請輸入 `pipenv run python -m django --version` 105 | 106 | 如果出現 2.0 以上就代表你有順利的安裝好。 107 | -------------------------------------------------------------------------------- /forms/README.md: -------------------------------------------------------------------------------- 1 | # Django Forms & Django Views 的結合 2 | 3 | 在前面我們介紹了 Django Admin 可以來對我們的 Model 做 CRUD 的動作,但是或許你還是會希望自己手刻一個新增文章的界面,那麼該怎麼做呢?傳統的 framework 可能會需要處理以下的事情: 4 | 5 | * 用 HTML 刻個 form 6 | * 處理 HTTP POST request 7 | * 檢查表單欄位內容是否正確 8 | * 把確認過的資料存進 database 當中 9 | 10 | 在 Django 當中,我們可以很輕鬆地做到這件事情。首先,先讓我們介紹 Django Form 這個 Django 當中很重要的 feature。 11 | 12 | ## Django Form 13 | 14 | 當我們有了一個 Model 之後,如果希望在頁面上面可以更新那個 Model,最簡單的方式就是生出一個表單,表單上面有 Model 所需要的欄位。當使用者填好欄位按下送出之後, 15 | 再由 web framework 處理送進來的資料,做完 validation,存進 database。 16 | 17 | 在 Django 當中提供了 Django Form 讓你可以很輕鬆的做完這件事情,讓我們來看看怎麼做吧! 18 | 19 | 首先讓我們在 article/views.py 當中新增以下的程式: 20 | 21 | ```python 22 | from django import forms 23 | 24 | class ArticleForm(forms.ModelForm): 25 | class Meta: 26 | model = Article 27 | fields = ['title', 'content', ] 28 | ``` 29 | 30 | 31 | 如此我們就創造了一個依照 Article Model 的 Django Form 類別,它繼承自 [ModelForm](https://docs.djangoproject.com/en/2.0/topics/forms/modelforms/) 而表單的欄位是 'title' 跟 'content' 這兩個欄位。 32 | 33 | 那麼我們要如何來使用 ArticleForm 呢?當然是在 view function 還有 template 當中來使用。在 article/views.py 當中新增以下的程式碼: 34 | 35 | ```python 36 | from django.http import HttpResponseRedirect 37 | 38 | def article_form(request): 39 | if request.method == 'POST': 40 | form = ArticleForm(request.POST) 41 | if form.is_valid(): 42 | new_article = form.save() 43 | return HttpResponseRedirect('/article/' + str(new_article.pk)) 44 | 45 | form = ArticleForm() 46 | return render(request, 'article_form.html', {'form': form}) 47 | ``` 48 | 49 | 在這邊,我們定義了一個 create view,接著我們透過 [request.method](https://docs.djangoproject.com/en/2.0/ref/request-response/#django.http.HttpRequest.method) 來判斷接下來的行為。如果是一般的 method,是創建一個 ArticleForm 的 instance,並且把它傳進去 create_article.html 的 template 當中。如果 method 為 POST,Django request 會把 POST 的資料都放到 [request.POST](https://docs.djangoproject.com/en/2.0/ref/request-response/#django.http.HttpRequest.POST) 當中,我們再把 request.POST 傳入 ArticleForm 當作 ArticleForm 的 constructor。接著透過 ```is_valid()``` 這個 method 來檢查輸入資料是否合法,如果是的話就存起來,最後再把網頁 redirect 到這篇的網址。 50 | 51 | 接下來我想大家也知道要幹什麼了,新增 article/templates/article_form.html 這個檔案。內容如下: 52 | 53 | ```html 54 | 55 | 56 | 57 |
58 | {% csrf_token %} 59 | {{ form.as_p }} 60 | 61 |
62 | 63 | 64 | ``` 65 | 66 | 這邊我們透過了 form.as_p 這個 method 把 form 給 render 出來,另外在這邊我們看到了 [csrf_token](https://docs.djangoproject.com/en/2.0/ref/templates/builtins/#std:templatetag-csrf_token) 這個奇怪的 template tag,這個 template tag 的意義是做 [Cross Site Request Forgery protection](https://docs.djangoproject.com/en/2.0/ref/contrib/csrf/),為了防止別的網站對你的站台做攻擊。細節我們在這邊不多說,可以參考 Django 官方文件有說明。這邊只要記得當你在做 POST 的時候要記得加上 csrf_token 這個 template tag 在 form 當中送出。 67 | 68 | 最後我們再 blog/urls.py 當中加上一段 code 來把 url 跟 views 串起來: 69 | 70 | ```python 71 | 72 | from article.views import article_form 73 | 74 | 75 | urlpatterns = [ 76 | ... 77 | path('create/', article.views.article_form), 78 | ... 79 | ] 80 | ``` 81 | 82 | 打開瀏覽器看看 http://localhost:8000/create/ ,試試看你的表單吧! 83 | -------------------------------------------------------------------------------- /views_revisited/README.md: -------------------------------------------------------------------------------- 1 | # Django Views, Django URL & Django Template 再訪 2 | 3 | 到目前為止我們了解到 Django URL, Django View, Django Model 還有 Django Template 的基礎,在這個階段我們把之前所學來做個整合吧! 4 | 5 | ## 單篇文章的頁面 6 | 7 | 首先,我們先來做單篇文章的頁面。我們在這邊的目標是讓網站能夠根據 URL 為 article/1/, article/2/, ..., 等等不同的 URL,把相對應 primary key 的 article 從資料庫中取出來並且把資料 response 到瀏覽器上。 8 | 9 | 首先我們先從 views 寫起,打開 article/views.py,加上這些 code 10 | 11 | ```python 12 | from django.shortcuts import render 13 | from .models import Article 14 | 15 | def article_detail(request, pk): 16 | article = Article.objects.get(pk=pk) 17 | return render(request, 'article.html', {'article': article}) 18 | ``` 19 | 20 | 在這邊我們寫了一個叫做 `article_detail` 的 view,傳入的參數除了 request 之外又多了 pk 這個參數,我們稍待會來講如何從 url 當中取出來 pk 的值。 21 | 22 | 接著我們就來把 url 跟 views 做結合,打開 blog/urls.py,加上這些 code 23 | 24 | ```python 25 | from article.views import article_detail 26 | 27 | urlpatterns = [ 28 | ... 29 | url(r'article//', article_detail), 30 | ] 31 | ``` 32 | 33 | 在前面提過,透過 route 定義 URL 的規則,讓 Django 對應到 view function。在這邊,route 除了可以使用固定字串之外,我們還可以還可以用動態的 URL。這邊的 `article//` 代表的意義如下: 34 | 35 | 1. `article/` 代表 URL 的開頭是 **article/** 36 | 2. `/` 這邊代表在 `article/` 後面接的是數字 (int),並且將其對應的數字以 `pk` 這個名稱傳入對應的到 view function 當中 37 | 38 | 這邊的 `int` 在 Django 當中稱作 [converter](https://docs.djangoproject.com/en/2.0/topics/http/urls/#path-converters),Django 預設提供了以下幾種 converter 39 | 40 | * str: 對應到任何的非空字串,這邊會排除掉 `/` 這個字元 41 | * int: 對應到各種正整數 42 | * slug: 我們常常會在網址當中像是看到使用 slug 而不是 pk 作爲網址,像是 `building-your-1st-django-site` 這種字串 43 | * uuid: uuid 是在網站、資料庫當中很常使用的,在某些狀況下,我們會透過 UUID 來代替資料庫當中的 pk。uuid 這個 converter 會回傳 UUID,舉例來說,像是 `075194d3-6885-417e-a8a8-6c931e272f00`。這個 converter 會回傳一個 [UUID](https://docs.python.org/3/library/uuid.html#uuid.UUID) 實例。 44 | * path: 跟 `str` converter 類似,會對應到任何的非空字串,跟 `str` 不同的是 `path` 會包含 `/` 這個字元。 45 | 46 | 最後要來寫 template,在 article/tempaltes 目錄底下新增一個 `article_detail.html`,內容如下: 47 | 48 | ```html 49 | 50 | 51 | 52 | {{ article.title }} 53 | 54 |

{{ article.title }}

55 |

{{ article.category.name }}

56 |
57 | {{ article.content }} 58 |
59 | 60 | ``` 61 | 62 | 在 tempalte 當中,這邊我們把從 `article_detail` 這個 view 當中傳入的 `article.title` 以及 `article.content` 在 template 當中作變數代換顯示在頁面上面。打開瀏覽器的 http://localhost:8000/article/1/ 看看,應該會輸出你的第一篇文章內容。 63 | 64 | 65 | ## 列出所有文章的頁面 66 | 67 | 接下來,我們來製作列出所有文章的頁面。跟製作單篇文章的頁面一樣,我們先從 views 開始寫起。打開 article/views.py,加上這些程式碼 68 | 69 | ```python 70 | def article_list(request): 71 | articles = Article.objects.all() 72 | return render(request, 'article_list.html', {'articles': articles}) 73 | ``` 74 | 75 | 在這邊我們寫了一個叫做 `article_list` 的 view,先用 `Article.objects.all()` 取出所有的 Article 再傳入 `article_list.html` 這個 template 當中。 76 | 77 | 接着來寫 template,在 article/tempaltes 目錄底下新增一個 `article_list.html`,內容如下: 78 | 79 | ```html 80 | 81 | 82 | 83 | Article List 84 | 85 |
86 | {% for article in articles %} 87 |

{{ article.title }}

88 |
{{ article.content }}
89 | {% endfor %} 90 |
91 | 92 | ``` 93 | 94 | ### Template Tags 95 | 96 | 相信來到這邊,對於 `article_list.html` 裡面大部分的內容都沒問題了。不過這邊出現了一個之前沒看過的東西,`{% for %}` 到 `{% endfor %}` 的區塊。這部分是什麼呢?在 Python 當中,如果我們要取出一個 list 當中的所有值我們會用 [for ... in](https://docs.python.org/3/tutorial/controlflow.html#for-statements) 這種語法,在 Django 當中也有提供類似的機制。在底下這段程式碼當中的 `[{% for %}](https://docs.djangoproject.com/en/2.0/ref/templates/builtins/#for)` 被稱作 template tags。 97 | 98 | ```html 99 | {% for article in articles %} 100 |

{{ article.title|title }}

101 |
{{ article.content }}
102 | {% endfor %} 103 | ``` 104 | 105 | 這邊可以看到 `[for](https://docs.djangoproject.com/en/2.0/ref/templates/builtins/#for)` 這個 template tag 的語法其實跟 Python 當中的 [for](https://docs.python.org/3/tutorial/controlflow.html#for-statements) 語法十分的接近。它會取出 articles 這個 list 當中所有的元素並且一一列出來。 106 | 107 | ### Template Filters 108 | 109 | 除了 template tags ,Django 也內建也許多的 template filters。Filter 的功用是在轉換輸入的變數。它們看起來會像是以下的形式: 110 | 111 | ```html 112 | {{ article.title|title}} 113 | ``` 114 | 115 | 如果 `article.title` 的內容是 "This is a book",那麼上面的 template 會輸出爲 116 | 117 | ```html 118 | This Is A Book 119 | ``` 120 | 121 | 除了 for 跟 title 之外,Django 也內建了許多 [template tags 以及 template filters](https://docs.djangoproject.com/en/2.0/ref/templates/builtins/),我們可以依據我們的需求選用。以下列出一些比較常用的 [template tags 以及 template filters](https://docs.djangoproject.com/en/2.0/ref/templates/builtins/)。 122 | 123 | * for 124 | * if 125 | * extends 126 | * block 127 | * include 128 | * csrf_token 129 | * url 130 | * date 131 | * default 132 | * length 133 | * safe 134 | 135 | 最後我們就來把 url 跟 views 做結合,打開 blog/urls.py,加上這些 code 136 | 137 | ```python 138 | from article.views import article_list 139 | 140 | urlpatterns = [ 141 | ... 142 | url(r'', article_list), 143 | ] 144 | ``` 145 | 146 | 打開瀏覽器的 http://localhost:8000/ 看看,應該會輸出你的所有文章內容。 147 | -------------------------------------------------------------------------------- /models/README.md: -------------------------------------------------------------------------------- 1 | # Django 與資料庫的互動 - Django Model 2 | 3 | 這個章節我們會講到 Django 要如何跟資料庫做互動。 4 | 5 | ## Setting Database 6 | 7 | 使用 Django 的最大好處之一就是 Django 原生支援許多的資料庫,只要經過簡單的設定,你可以輕鬆從 sqlite 轉換到 MySQL 甚至是 Oracle。為了我們現在開發方便,我們就先用最簡單的 sqlite 吧! 8 | 9 | Django 當中跟資料庫相關的設定,都在 settings.py 當中。打開 blog/settings.py 這個檔案,會看到如下的程式碼: 10 | 11 | ```python 12 | DATABASES = { 13 | 'default': { 14 | 'ENGINE': 'django.db.backends.sqlite3', 15 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 16 | } 17 | } 18 | ``` 19 | 20 | 在預設設定中,Django 指定了 database engine 為 sqlite3,並將它放在 `BASE_DIR` 這個目錄(代表你的專案最外層目錄)。你也可以使用其他資料庫,官方支援的除了 SQLite 外尚有 PostgreSQL、MySQL 與 Oracle,另外也有一些非官方的套件可以支援其他資料庫。大部份的資料庫系統中,通常需要指定 database 名稱、使用者、密碼、HOST 以及 PORT,在這裡我們為了方便說明起見,直接使用預設的 SQLite 設定。 21 | 22 | 23 | ## Django Model 24 | 25 | 在 Django 當中,我們是透過 Django Model 來跟資料庫做互動。在這邊,我們透過寫 Django Model,讓資料庫能夠產生相對應的 Table,關於 Model 基本的概念如下: 26 | 27 | * 每一個 Django Model 都繼承自 `django.db.models.Model` 28 | * 在 Model 當中的每一個 attribute 都代表了一個 database field 29 | * Django 讓我們可以透過 Model API 來執行 database query,這代表你可以儘量不用寫 SQL 30 | 31 | 既然這是一個 blog 網站,那麼首先我們當然要來建立一個儲存文章的 Model。另外我們也希望建立一個儲存類別(category) 的 Model。 32 | 33 | 關於 Model 的資訊,我們都會放在 APP 目錄當中的 models.py 裡面。打開 articles/models.py,輸入 34 | 35 | 36 | ```python 37 | from django.db import models 38 | 39 | class Category(models.Model): 40 | name = models.CharField(max_length=50) 41 | 42 | def __str__(self): 43 | return self.name 44 | 45 | class Article(models.Model): 46 | content = models.TextField() 47 | title = models.CharField(max_length=50) 48 | category = models.ForeignKey('Category', blank=True, null=True, on_delete=models.SET_NULL) 49 | 50 | def __str__(self): 51 | return self.title 52 | ``` 53 | 54 | 55 | 在此,我們建立了兩個 Model,一個是 Category,代表了類別,另外一個則是 Article,代表了文章。這兩個 Model 都繼承自 django.db.models.Model。 56 | 57 | 首先先讓我們看看 Category 這個 Model。這個 Model 我們宣告了一個叫做 name 的 attribute,它的形態是 `[models.CharField](https://docs.djangoproject.com/en/2.0/ref/models/fields/#django.db.models.CharField)`,另外 max_length 則代表了 name 最大長度為 50。 58 | 59 | 此外,我們也宣告了一個 `__str__(self)` function 來表示 Category 物件要如何以 unicode 表示自己,在此我們直接用類別的名字做表示。 60 | 61 | Article 這個 Model 跟 Category Model 很類似,我們有三個屬性,content 代表文章內容,title 代表標題,category 是代表 Article 跟 Category 會建立起資料庫當中的關聯性,在這邊我們用 ForeignKey 來建立起關係。我們可以看到 `[models.ForeignKey](https://docs.djangoproject.com/en/2.0/ref/models/fields/#django.db.models.ForeignKey)` 裡面傳了四個參數,分別如下: 62 | 63 | * `Category`: 代表要跟那個 Model 建立起 ForeignKey 的關係 64 | * `[null](https://docs.djangoproject.com/en/2.0/ref/models/fields/#null)`: 這個值代表着在資料庫當中,這個欄位可以以 NULL 存空值。注意如果是在 CharField 或是 TextField 當中,通常我們不會設定 `null=True`。原因是在 Django 當中,我們通常會用空字串來表達沒有值。如果又多設定了 `null=True` 的話,我們在判定這個欄位有沒有值的時候就會有兩種可能的情況要判斷。 65 | * `[blank](https://docs.djangoproject.com/en/2.0/ref/models/fields/#blank)`: 這個值代表欄位是否可以允許是空的。注意一下這個值跟 null 是有不同的,null 是在資料庫層級來做判斷,但是 blank 則是跟驗證 (validation) 相關。如果 `blank=True`,那麼代表當我們使用表單 (form) 的時候可以允許這個欄位是空的,否則這個欄位就是必須的。等到後面的 Django Form 會有更詳細的說明。 66 | * `[on_delete](https://docs.djangoproject.com/en/2.0/ref/models/fields/#django.db.models.ForeignKey.on_delete)`: 這邊是設定當這個 model 被刪除的時候,跟他有關聯的 Model 預設行爲爲何。讓我們用上面的例子來說明不同的參數設定在當 Category 被刪除的時候,會造成的行爲: 67 | 68 | * `CASCADE`: 相關的 Article 也會被刪除 69 | * `PROTECT`: 如果還有跟 Category 有關聯的 Article,那麼會丟出一個 `[ProtectedError](https://docs.djangoproject.com/en/2.0/ref/exceptions/#django.db.models.ProtectedError)` 70 | * `SET_NULL`: 會把 ForeignKey 設成 null 71 | * `SET_DEFAULT`: 會把 ForeignKey 的值設成預設的值 72 | * `SET()`: 會把 ForeignKey 的值設成指定的值 73 | * `DO_NOTHING`: 什麼事情都不做。 74 | 75 | 76 | ## 實際建立資料表 77 | 78 | 上面的 code 只是告訴 Django table 要長什麼樣子,接下來要真正的在資料庫中把 table 生出來。 79 | 80 | 要把 table 生出來一樣要使用 manage.py 這個指令,我們透過 syncdb 來產生 table。syncdb 會根據 settings.py 裡面 INSTALLED_APPS 當中的 Django APP 當中的 models.py 中的 Model 生出相對應的 table,打開你的 shell 輸入: 81 | 82 | ```shell 83 | pipenv run python manage.py makemigrations 84 | pipenv run python manage.py migrate 85 | ``` 86 | 87 | 這邊我們可以看到兩個指令,分別危 makemigartions 以及 migrate,分別介紹如下: 88 | 89 | * `[makemigartions](https://docs.djangoproject.com/en/2.0/ref/django-admin/#django-admin-makemigrations)` 會根據你對 models.py 當中欄位以及 Model 的新增、刪除或是修改建立新的 migration 檔案,當 migrate 指令執行的時候時可以照著這份紀錄更新資料庫。 90 | * `[migrate](https://docs.djangoproject.com/en/2.0/ref/django-admin/#django-admin-migrate)` 會建立或更新資料表裡面的內容,也就是實際去執行剛剛 makemigrations 之後產生的 python 程式,將你對 models.py 裡的修改跟實際的資料庫欄位同步。 91 | 92 | 93 | ## 讓我們來玩玩 Model 吧 94 | 95 | 在 migrate 之後,我們在 terminal 中輸入 96 | 97 | ``` 98 | pipenv run python manage.py shell 99 | ``` 100 | 101 | 來開啟一個跟原生 python 很相像的 interactive shell,跟一般 python 的差別只有我們可以在這個 shell 當中存取 Django Project 當中的 Model 等等資訊。 102 | 103 | 打開 shell 之後,我們輸入下面的指令 104 | 105 | ```python 106 | >>> from article.models import Article, Category 107 | >>> Article.objects.create(content="Test1", title="article 1") 108 | >>> Article.objects.create(content="Test2", title="article 2") 109 | >>> c = Category.objects.create(name="category 1") 110 | >>> Article.objects.create(content="Test3", title="article 3", category=c) 111 | ``` 112 | 113 | 在這邊,我們創建了 3 個 Article 物件,把它們塞到了 database 當中。可以看到我們在這邊沒有寫任何的 SQL 就完成了 insert 資料到 database 的動作。 114 | 115 | 如果要查詢所有 Article 的資料, 116 | 117 | ```python 118 | >>> Article.objects.all() 119 | >>> for article in Article.objects.all(): 120 | >>> print(article.title) 121 | ``` 122 | 123 | 取出一個 title 為 "article 1" 的 Model,修改它的 title 之後再儲存。 124 | 125 | ```python 126 | >>> a = Article.objects.get(title="article 1") 127 | >>> a.title = "Article" 128 | >>> a.save() 129 | ``` 130 | 131 | 其他更多的 query API 可以參考 [Django 的官方文件](https://docs.djangoproject.com/en/1.6/ref/models/querysets/),透過 Django Model 提供的 API,讓你幾乎可以不用寫 SQL 就可以完成許多跟 Database 的操作。 132 | 133 | ## 練習 134 | 135 | * 除了我們有用到的 all(), create(), get() 等等方法之外,看看還有什麼 Queryset API 可以玩呢?玩玩看 `[delete()](https://docs.djangoproject.com/en/2.0/topics/db/queries/#deleting-objects)`, `[filter()](https://docs.djangoproject.com/en/2.0/topics/db/queries/#retrieving-specific-objects-with-filters)` 136 | * 每個 Article object 除了我們自定的那些欄位之外還有什麼欄位呢?看看 pk 這個欄位 137 | --------------------------------------------------------------------------------