Lecturer:Yan

Django

Basic

大綱

  • 課程目標
  • Web framework 介紹
  • Django 介紹
  • MTV 架構介紹
  • 虛擬環境介紹
  • Django 安裝
  • 建立 Django projects
  • Hello Worlds!
  • Models
  • OOP

Outline

GOAL

這兩堂課中你將會學到

  • 基本的物件導向
  • 用 Django 建立一個屬於自己的日誌網站

!! 本課程只是入門,並不會深入解釋所有概念 !!

有興趣的話可以加入 SIRLA 或是繼續自學 ouo

Web framework 介紹

Web framework ?

網頁框架就是別人已經設定好的一個網站模板,你可以學習它的規則,然後修改成自己需要的樣子。簡單來說就是當你開發 Web 應用程式時所用的框架。

通常會提供:

  • 一個既定的程式骨架
  • 強大且豐富的函式庫 ( Libraries )

常見的網頁框架

常用 Python 框架比較 

  • 大而全
  • 內建全套解決方案
  • 注重組件的重用性、可插拔性
  • 微框架
  • 自由、靈活,可擴展性強
  • 入門簡單

框架本身無法自行運作,開發者要將框架搭配上自己的程式,才是一個完整的應用程式。

Django 介紹

Introduction

Django ?

  • 免費開放原始碼
  • 著重快速開發、高效能
  • 遵從 DRY 守則,致力於淺顯易懂和優雅的程式碼
  • 使用 MTV 架構
  • 是 Python 最著名的 Web Framework,可以快速開發安全和可維護的網站。

它有以下幾個特色:

DRY

Don't Repeat Yourself

  • 原則是「系統中的每一部分,都必須有一個單一的、明確的、權威的代表」。
  • 指的是代碼必須能夠表達所應表達的內容,但是不能含有任何重複代碼。
  • 當 DRY 原則被成功應用時,一個系統中任何單個元素的修改都不需要與其邏輯無關的其他元素發生改變。

實例

Text

實例

MTV 架構介紹

Introduction

MVC

  • Model : 資料的管理(例如與資料庫的溝通) 、演算法邏輯(商業邏輯) 、物件結構定義
  • View : 呈現給使用者看、操作的介面
  • Controller :  依據傳入的資料該怎麼運作、程式流程的控制、該回傳給使用者什麼資料等

MVC

負責資料庫

要呈現哪一個資料,

並交由 Template 呈現

最後的 HTML 呈現

Why MTV ?

使用 MTV 架構的好處:

  • 避免 Spaghetti Code
  • 分離前後端
    • 前後端可獨立作業
    • 擁有更多彈性
    • 較容易維護
    • 降低程式複雜度

虛擬環境介紹

Introduction

  • 你的專案會擁有一個專屬的獨立 Python 環境。
  • 不需要 root 權限,就可以安裝新套件。
  • 方便控管不同版本的套件,不用擔心升級套件會影響到其他專案。

建立好後,會出現剛剛取名的資料夾,切換進去

$ cd mysite

// 如果你剛剛取不一樣的名字
$ cd 名字

$ 不用打,只要打後面的指令

$ cd 到你想放資料夾的地方
$ mkdir 隨便你取

建好你要當作虛擬環境的資料夾

$ cd 到資料夾

前往該資料夾

$ python -m venv 你想取的名字

// 舉例來說
$ python -m venv venv

創建虛擬環境

$ pip install virtualenv

如果你是用 mac 記得先安裝

$ 你剛剛取的虛擬環境名稱\Scripts\activate

for Windows

for Mac

$ source 你剛剛取的虛擬環境名稱/bin/activate

進入虛擬環境

$ pip install django

安裝 Django

$ pip list

可以先 exit 到虛擬環境外後,再輸入:

這時候你就會發現剛剛在虛擬環境裡安裝的套件,真的沒有在外面。

建立 Django project

Introduction

建立專案資料夾 - startproject

首先,使用 django-admin.py 來建立第一個 Django project mysite :

$ django-admin.py startproject mysite
// 這裡是以取名為 mysite 為例

$ django-admin.py startproject 這裡可以放你要的名字

啟動開發伺服器 - runserver

runserver 會啟動一個簡單的 web server,方便於在開發階段使用

$ cd mysite // 先進到剛剛建好的 project 資料夾
$ python manage.py runserver

建立 Django app

Introduction

建立 Django app

利用 startapp 建立一個 Django app - blog

$ python manage.py startapp blog
// 這裡是以取名為 blog 為例

$ python manage.py startapp 這裡可以放你要的名字

新增 app

打開 mysite/settings.py,找到 INSTALLED_APPS

# 檔案位置:mysite/settings.py
...
# Application definition

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blog', <--- !! 加在這裡 !!
)

Hello World!

Introduction

Django Views

Django view 其實是一個 function,處理 HttpRequest 物件,並回傳 HttpResponse 物件。

一個網頁程式當中的邏輯通常是這個樣子的:

在 Django 當中,處理這部分的邏輯稱之為 Django Views,通常我們都會放在 Django APP 當中的 views.py 檔案裡面。

request

進來

從資料庫

撈資料

處理

資料

把網頁

呈現出來

建立第一個 View

建立一個名為 hello_world 的 view

在 blog/views.py 輸入下列程式碼:

# 檔案位置:mysite/blog/views.py

from django.http import HttpResponse


def hello_world(request):
    return HttpResponse("Hello World!")

Django URL 設定

Django 需要知道 URL 與 view 的對應關係

例如有人瀏覽 http://127.0.0.1:8000/hello/ 時 ,hello_world() 這個 view function 需要被執行。

而這個對應關係就是 URL conf (URL configuration)。

URL Conf

現在來設定 Hello World 的 URL conf。

打開 mysite/urls.py,import 剛剛寫的 view function:

from blog.views import hello_world

在 urlpatterns 中加入下面這行:

url(r'^hello/$', hello_world),

urls.py 目前的長相

# 檔案位置:mysite/mysite/urls.py

from django.conf.urls import include, url
from django.contrib import admin
from blog.views import hello_world

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^hello/$', hello_world),
]

剛剛寫了什麼鬼 ?

url(regex, view)

像剛剛寫得 url(r'^hello/$', hello_world),
  • regex
    • 定義的 URL 規則
    • 規則以 regular expression 來表達
    • r'^hello/$' 代表的是 hello/ 這種 URL
  • view
    • 對應的 view function
    • 指的是 hello_world 這個 view

嗚呼,現在可以來說 Hello World 拉

現在啟動你的 web server,就像剛剛那樣:

$ cd ../ // 回到 mysite 資料夾
$ python manage.py runserver

在瀏覽器輸入 http://127.0.0.1:8000/hello/,你會看到網頁顯示我們在 HttpResponse 傳入的文字Hello World!

Templates

Introduction

建立資料夾

確認目前所在位置是在 mysite 裡

新增一個名為 templates 的資料夾

$ mkdir templates

設定 Templates 資料夾的位置

修改 mysite/settings.py 中的 TEMPLATES 設定

將 'DIRS' 原本的 [] 修改成:

[os.path.join(BASE_DIR, 'templates').replace('\\', '/')]

並在前面引入 os

import os

修改完的 TEMPLATES 設定應該要長這樣

# 檔案位置:mysite/mysite/settings.py

import os #前面要加入這句

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates').replace('\\', '/')],
        'APP_DIRS': True,
        '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',
            ],
        },
    },
]

在 templates 資料夾中新增一個 hello_world.html

<!-- 檔案位置:mysite/templates/hello_world.html -->

<!DOCTYPE html>
<html>
    <head>
        <title>I come from template!!</title>
        <style>
            body {
               background-color: 你想要的顏色;
            }
            em {
                color: 你想要的顏色;
            }
        </style>
    </head>
    <body>
        <h1>Hello World!</h1>
        <em>{{ current_time }}</em>
    </body>
</html>

建立 Template

hello_world.html 的完整長相

<!-- 檔案位置:mysite/templates/hello_world.html -->

<!DOCTYPE html>
<html>
    <head>
        <title>I come from template!!</title>
        <style>
            body {
               background-color: black;
            }
            h1 {
                color: white;
            }
            em {
                color: white;
            }
        </style>
    </head>
    <body>
        <h1>Hello World!</h1>
        <em>{{ current_time }}</em>
    </body>
</html>

讓 Hello World 變厲害一點

掏出(?) 剛剛改過的 blog/views.py

把 hello_world 修改一下

# 檔案位置:mysite/blog/views.py

from datetime import datetime
from django.shortcuts import render


def hello_world(request):
    return render(request, 'hello_world.html', {
        'current_time': str(datetime.now()),
    })

接著再打開來看看

$ python manage.py runserver

在瀏覽器輸入 http://127.0.0.1:8000/hello/

此時可以看到剛剛的模板被套用了,

而字跟背景會是你設定的顏色

將 view function hello_world 修改如下:

# 檔案位置:mysite/blog/views.py

from datetime import datetime
from django.shortcuts import render


def hello_world(request):
    return render(request, 'hello_world.html', {
        'current_time': str(datetime.now()),
    })

使用 render function

Models

Installation

Models

  • 為了使用資料庫來管理資料,透過 Models 來完成與資料庫的互動。
  • 使用 Models 時,資料庫轉換相當方便。
# 檔案位置:mysite/mysite/settings.py

...

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

settings.py 中設定了資料庫連線的預設值

這裡為了方便直接使用預設的 SQLite 3

Basic OOP

Installation

OOP

Object Oriented Programming (物件導向程式設計)

將功能抽象化後,用程式表達出來的一種程式設計方式

Objects

Class

設計圖

實例化

實際的東西

都可以當成 Object

class ClassName:
	你設定的 arrtibute 跟 method

Create a Class

class 的組成包含了

  • 事物的屬性(attribute)
  • 可做到的行為(method)

屬性分為兩種:

  • 類別屬性(class attribute)
  • 實例屬性(instance attribute)

Attributes

class motorcycle:

    # class attribute
    wheels = 2

    # instance attributes
    def __init__(self, color):
        self.color = color
# method 1
def showDescription(self):
  print("This motorcycle is ", self.color)

# method 2
def changeColor(self, color):
    self.color = color

簡單來說就是在 class 中加入函式

Methods

第一個參數一定要是 self,即使 method 沒用到它

Create a function

def 函式名稱(參數):
    程式碼
    return 某個值

一個函式的基本架構如下 :

def hello():
    print('Hello, World!')

建立一個最基本的函式

def hello():
    print('Hello, World!')

hello() # 這樣就是呼叫

呼叫這個函式

def hello(name):
	print('Hello,', name)

建立一個 帶參數 的函式

def hello(name):
    print('Hello,', name)

hello('yan') # 呼叫時要給參數值

呼叫這個函式

def sum(a, b):
    return a + b

建立一個帶有 return 的函式

def sum(a, b):
    return a + b

x = sum(3, 4) # 呼叫時要給參數值
print(x)

呼叫這個函式

class Human:
    type_name = 'human'
    
    def __init__(self, name, age):
      self.name = name
      self.age = age
          
    def eat(self):
      print("I'm eating.")

Class Human

Attribute
type name
name
age
Method
eat

來寫個叫 Human 的 class 吧

class Human:
    type_name = 'human'
    
    def __init__(self, name, age):
      self.name = name
      self.age = age
class Human:

延續剛剛的程式碼,建立一個叫 yan 的 object :

# 變數名稱 = 函式名稱(參數)
yan = Human('yan', 20)

Create a Object

現在測試一下這個 object

print(yan.name, yan.age)
yan.eat()

class Human 完整程式碼

class Human:
    type_name = 'human'
    
    def __init__(self, name, age):
      self.name = name
      self.age = age
          
    def eat(self):
      print("I'm eating.")
      
yan = Human('yan', 20)
print(yan.name, yan.age)
yan.eat()

如果你還是搞不懂 class,可以參考一下這篇https://www.learnbyexample.org/python-classes-and-objects/

或是現在叫我再講一次

  • 繼承是指,從原先有的 class 定義出新的 class 。
  • 子類別會擁有父類別的 attribute 跟 method
  • 可以將相同事情歸在同一大類中。

Inheritance

舉個例子

Class

Class

繼承

Attributes

  • Name
  • Language

Attributes

  • Name
  • Language: Chinese

Methods

  • Walk
  • Eat
  • Sleep
  • Drink

Methods

  • Walk
  • Eat
  • Sleep

Human

🇹🇼 Taiwanese

Objects

實例化

Attributes

  • Name: 小明
  • Language: Chinese

Methods

  • Walk
  • Eat
  • Sleep
  • Drink: bubble tea

小明

class Human:
    type_name = 'human'
    
    def __init__(self, name, age):
      self.name = name
      self.age = age
          
    def eat(self):
      print("I'm eating.")

class Taiwanese(Human):
    def __init__(self, name, age):
    	super().__init__(name,age)
        self.language = 'Chinese'
    
    def drink(self, typeofdrink):
        print("I drink %s"%typeofdrink)

先建立父類別(Human)

class Human:
    type_name = 'human'
    
    def __init__(self, name, age):
      self.name = name
      self.age = age
          
    def eat(self):
      print("I'm eating.")
class Human:
    type_name = 'human'
    
    def __init__(self, name, age):
      self.name = name
      self.age = age
          
    def eat(self):
      print("I'm eating.")

class Taiwanese(Human):

再建立子類別(Taiwanese)

繼承

可以另外增加屬於子類別的 attribute 或 method

class Human:
    type_name = 'human'
    
    def __init__(self, name, age):
      self.name = name
      self.age = age
          
    def eat(self):
      print("I'm eating.")

class Taiwanese(Human):
    def __init__(self, name, age):
    	super().__init__(name,age)
yan = Taiwanese('yan',20)
print(yan.name(), yan.language())
yan.eat()
yan.drink('bubble tea')

建立 object ,測試一下剛剛寫的繼承

class Human:
    type_name = 'human'
    
    def __init__(self, name, age):
      self.name = name
      self.age = age
          
    def eat(self):
      print("I'm eating.")

class Taiwanese(Human):
    def __init__(self, name, age):
    	super().__init__(name,age)
        self.language = 'Chinese'
    
    def drink(self, typeofdrink):
        print("I drink %s"%typeofdrink)

yan = Taiwanese('yan',20)
print(yan.name, yan.language)
yan.eat()
yan.drink('bubble tea')

繼承的完整程式碼

Create a blog post model

Installation

定義 Models 的 object

# 檔案位置:mysite/blog/models.py

from django.conf import settings
from django.db import models
from django.utils import timezone


class Post(models.Model):
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    title = models.CharField(max_length=200)
    text = models.TextField()
    created_date = models.DateTimeField(default=timezone.now)
    published_date = models.DateTimeField(blank=True, null=True)

    def publish(self):
        self.published_date = timezone.now()
        self.save()

    def __str__(self):
        return self.title

打開 blog/models.py,刪掉所有東西然後改成:

開始一行一行解釋到底打了什麼囉 ouo

from django.conf import settings
from django.db import models
from django.utils import timezone

首先 import 一些會用到的套件

目標:建立一個 blog 文章資料庫

  • title
  • text
  • author
  • created_date
  • published_date

而一篇文章中,應該會有以下這些元素

class Post(models.Model):

因為這個 class 是繼承 django.db.models.Model

所以後面小括號要塞進 models.Model

def publish(self):

在 class 中建立一個叫 publish 的 method

將 publish date 指派為當前的時間、儲存

self.published_date = timezone.now()
self.save()
def __str__(self):
	return self.title

定義這個 object 的字串描述

author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

外來鍵

代表對應到哪個 class

當對應的類別被刪除之後

這些對應到別人的資料要怎麼被處理

Primary key

  • 每個資料表都必須要有一個主鍵的欄位。
  • 主鍵不能為空值。
id name
093 Erica
237 Julie
521 Erica

Foreign Key

  • 用來建立不同資料表之間的關係。
  • 一定是其他資料表的主鍵。
id name class
093 Erica 1
237 Julie 2
521 Erica 3
1 A班
2 B班
3 C班
class_id name

CharField:字串欄位

title = models.CharField(max_length=200)

設定可包含之字元個數

text = models.TextField()

TextField:沒有長度限制的長文本

非必填欄位

created_date = models.DateTimeField(default=timezone.now)

published_date = models.DateTimeField(blank=True, null=True)

DateTimeField:日期與時間欄位

可為空

Create tables

Installation

$ cd 到 mysite
$ python manage.py makemigrations blog

因為我們在 models.py 做了更動,

所以要告訴 Django 我們修改了一些內容

blog 是你的 app 名稱

$ Migrations for 'blog':
    blog/migrations/0001_initial.py
      - Create model Post

完成後會出現以下的文字敘述

$ python manage.py migrate blog

接著將 Post 這個 model 放進資料庫

blog 是你的 app 名稱

$ Operations to perform:
    Apply all migrations: admin, auth, blog...
  Running migrations:
    Applying contenttypes.0001_initial... OK
    Applying auth.0001_initial... OK
    ...

完成後會出現類似的文字敘述

Django admin

Installation

Django Admin ?

  • Django 內建的一個 App
  • 經設定可用來管理後台

首先我們要來同步 Django 專案下 models.py 中

預設的類別(Class) 及資料庫

$ python manage.py migrate
$ python manage.py createsuperuser

而要使用 Django 的管理後台,

我們需要一個管理員帳號。

接著就照著指示建立好帳號,創建密碼時是不會顯示的,要自己記得打到哪裡

# 檔案位置:mysite/blog/admin.py

from django.contrib import admin
from .models import Post

admin.site.register(Post)

還要讓 Django 知道,有哪些 Model 需要管理後台。

修改 blog/admin.py

$ python manage.py runserver

完成後連至 http://127.0.0.1:8000/admin

即可看到管理後台的登入頁面:

登入後畫面

如果剛剛有註冊好你需要 Django 管理後台的 Model,這邊就會出現它

按下 add posts,就能看到我們剛剛寫的那些欄位

新增一篇文章試試看

建立首頁

Installation

# ...
from blog.models import Post

def home(request):
    post_list = Post.objects.all()
    return render(request, 'home.html', {
        'post_list': post_list,
    })

在 blog/views.py 內新增

建立首頁的 view

# 檔案位置:mysite/blog/views.py

from datetime import datetime
from django.shortcuts import render
from blog.models import Post

def home(request):
    post_list = Post.objects.all()
    return render(request, 'home.html', {
        'post_list': post_list,
    })

def hello_world(request):
    return render(request, 'hello_world.html', {
        'current_time': str(datetime.now()),
    })

目前完整的 blog/views.py

# 檔案位置:mysite/mysite/urls.py

from django.conf.urls import include, url
from django.contrib import admin
from diary.views import hello_world, home # 這邊要新增

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^hello/$', hello_world),
    # 還有這裡也要新增
    url(r'^$', home),
]

將 mysite/mysite/urls.py 修改

設定首頁的 URL

<!-- 檔案位置:mysite/templates/home.html -->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>My blog</title>
  </head>
  <body>
    <h1>Hello! This is my blog</h1>
    <div class="container">
        {% for post in post_list %}
            <div class="post">
                <h2><a href="{% url 'post_detail' pk=post.pk %}">{{ post.title }}</a></h2>
                <p>{{ post.created_date }}</p>
                <p>{{ post.text }}</p>
            </div>
        {% endfor %}
    </div>
  </body>
</html>

在 templates 資料夾中新增一個 home.html

建立首頁的 Template

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
      	# 修改下面這行
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
      
        'APP_DIRS': True,
        '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',
            ],
        },
    },

確定一下 mysite/mysite/settings.py 是否長這樣

更改 settings.py

接著再打開來看看

$ python manage.py runserver

現在一打開你就能看到剛剛新增好的首頁啦

建立 Post

Installation

from django.shortcuts import render
from django.http import HttpResponse
from blog.models import Post

def hello_world(request):
    return HttpResponse("Hello World!")

def home(request):
  post_list = Post.objects.all()

  return render(request, 'home.html', {
    'post_list': post_list,
  })

# 新增這邊
def post_detail(request, pk):
  post = Post.objects.get(pk=pk)
  return render(request, 'post.html', {'post':post})

在 mysite/blog/views.py 內新增

建立 Post 的 view

from django.conf.urls import include, url
from django.contrib import admin
from blog.views import hello_world, home, post_detail #新增這裡

urlpatterns = [
  url(r'^admin/', admin.site.urls),
  url(r'^hello/$', hello_world),
  url(r'^$', home),
  # 還有這裡也要新增
  url(r'^post/(?P<pk>\d+)/$', post_detail, name='post_detail'), 
]

修改 mysite/mysite/urls.py

設定文章的 URL

建立文章介面

Installation

在 blog 資料夾內建立一個 static 資料夾

裡面再建立一個 css 資料夾

先來開個資料夾

venv
mysite/
├── manage.py
├── mysite   
├── templates
└── blog
    ├── static
        └── css

h1 a {
    color: orange;
}

h1{
    text-align: center;
    color: #8CB2D0;
}

h2{
    text-align: center;
    color: #8CB2D0;
    font-style:italic;
}

body p {
    text-align: center;
    font-style:italic;
}

.post {
    color: #A89797;
    font-family: 'Dancing Script', cursive;
}

.page-header {
    background-color: #B6533E;
    margin-top: 0;
    padding: 20px 20px 20px 40px;
}

.container{
    display: flex;
    justify-content: space-around;
}

建立 mysite/blog/static/css/blog.css

{% load static %}
<html>
  <head>
    <meta charset="utf-8">
    {% block title %}
    {% endblock %}

    <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
    <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
    <link rel="stylesheet" href="{% static 'css/blog.css' %}">
    <link href="https://fonts.googleapis.com/css2?family=Dancing+Script:wght@500&display=swap" rel="stylesheet"> 
  </head>
  <body>
    <div class="page-header">
      <h1><a href="/">My Blog</a></h1>
    </div>
    {% block content %}
    {% endblock %}
  </body>
</html>

mysite/templates/base.html

建立 base.html

{% extends "base.html" %}

{% block title %}
    <title>test blog</title>
{% endblock %}

{% block content %}
    <h2>Hello! this is my blog</h2>
    <div class="container">
        {% for post in post_list %}
        <div class="post">
            <h2><a href="{% url 'post_detail' pk=post.pk %}">{{ post.title }}</a></h2>
            <p>{{ post.created_date }}</p>
            <p>{{ post.text|linebreaksbr|slice:":30" }}</p>
        </div>
        {% empty %}
            <p>敬請期待</p>
        {% endfor %}
    </div>
{% endblock %}

mysite/templates/home.html

修改 home.html

{% extends "base.html" %}
{% block title %}
    <title>{{ post.title }} | test blog</title>
{% endblock %}

{% block content %}
    <div class="post">
        <h2><a href="#">{{ post.title }}</a></h2>
        <p>{{ post.created_date }}</p>
        <p>{{ post.text }}</p>
    </div>
{% endblock %}

mysite/templates/post.html

新增 post.html

新增一篇文章

連至 http://127.0.0.1:8000/admin,從管理後台新增一篇測試用文章

$ python manage.py runserver

接著打開首頁 http://127.0.0.1:8000/ 測試看看

應該會看到剛剛新增好的文章,也能點擊進去

加上 navbar

Installation

{% load static %}
<html>
<head>
    <meta charset="utf-8">
    {% block title %}
    {% endblock %}

    <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
    <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
    <link rel="stylesheet" href="{% static 'css/blog.css' %}">
    <link href="https://fonts.googleapis.com/css2?family=Dancing+Script:wght@500&display=swap" rel="stylesheet"> 
</head>
<body>
    <nav class="navbar">
        <a class="navbar-brand" href="/">My blog</a>
        <a class="navbar-brand" href="https://github.com/">My github</a>
        <a class="navbar-brand" href="/admin">Sign in</a>
    </nav>
    <div class="page-header">
        <h1><a href="/">My Blog</a></h1>
    </div>
    {% block content %}
    {% endblock %}
</body>
</html>

mysite/templates/base.html

修改 base.html

/*新增這邊*/
.navbar {
    list-style-type: none;
    margin: 0;
    padding: 0;
    background-color: #FCA205;
}
   
.navbar a{
    color: #FFFFFF;
}
/*到這邊*/

h1 a {
    color: #FCA205;
}

h1{
    text-align: center;
    color: #8CB2D0;
}

h2{
    text-align: center;
    color: #8CB2D0;
    font-style:italic;
}

body p {
    text-align: center;
    font-style:italic;
}

.post {
    color: #A89797;
    font-family: 'Dancing Script', cursive;
}

.page-header {
    background-color: #B6533E;
    margin-top: 0;
    padding: 20px 20px 20px 40px;
}

.container{
    display: flex;
    justify-content: space-around;
}

修改 mysite/blog/static/css/blog.css

你的首頁 http://127.0.0.1:8000/ 就會有 navbar 啦

而上面的連結能點擊進去

部署

Installation

$ pip install dj-database-url gunicorn dj-static
$ pip install heroku psycopg2-binary

套件安裝

接著將套件全部條列出來

$ pip freeze > requirements.txt

並在 requirements.txt 中加入 psycopg2==2.8.5

大概會長得像下面這樣

asgiref==3.3.1
certifi==2020.12.5
chardet==4.0.0
dj-database-url==0.5.0
dj-static==0.0.6
Django==3.1.7
gunicorn==20.0.4
heroku==0.1.4
idna==2.10
psycopg2-binary==2.8.6
python-dateutil==1.5
pytz==2021.1
requests==2.25.1
sqlparse==0.4.1
static3==0.7.0
urllib3==1.26.4
psycopg2==2.8.5

在 mysite 中(第一層)新增叫做 Procfile 的檔案

web: gunicorn --pythonpath mysite mysite.wsgi

mysite

├── Procfile
├── blog
├── db.sqlite3
├── manage.py
├── mysite
├── requirements.txt
└── templates

在 mysite/mysite 中(第二層)新增叫做 production_settings.py 的檔案

# 檔案位置:mysite/mysite/production_settings.py

# Import all default settings.
from .settings import *

import dj_database_url
DATABASES = {
    'default': dj_database_url.config(),
}

# Static asset configuration.
STATIC_ROOT = 'staticfiles'

# Honor the 'X-Forwarded-Proto' header for request.is_secure().
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

# Allow all host headers.
ALLOWED_HOSTS = ['*']

# Turn off DEBUG mode.
DEBUG = False

修改 wsgi.py

# 檔案位置:mysite/mysite/wsgi.py

import os

from django.core.wsgi import get_wsgi_application

from dj_static import Cling

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")

application = Cling(get_wsgi_application())

新增 .gitignore

# 檔案位置:mysite/.gitignore

venv #這裡是你的虛擬環境名稱
*.pyc
__pycache__
staticfiles
db.sqlite3

目前的檔案結構

mysite
├──mysite
│   ├── blog
│   │   ├── __init__.py
│   │   ├── production_settings.py
│   │   ├── settings.py
│   │   ├── urls.py
│   │   └── wsgi.py
│   ├── templates
│   └── manage.py
├── venv
├── .gitignore
├── Procfile
└── requirements.txt

Heroku

首先到官網註冊一下

建立 Git Repository

$ git init
$ git add .
$ git commit -m "add all"

-m 後面的訊息可自訂

加到環境變數中

$ set PATH=%PATH%;C:\Program Files\Heroku\bin #Heroku安裝的路徑

登入並新增新的 Heroku App

$ heroku login
$ heroku create

如果你想要自己取 app 的名稱,指令如下:

$ heroku create 這裡放app名稱

設定環境變數

$ heroku config:set DJANGO_SETTINGS_MODULE=mysite.production_settings

將專案上傳到 Heroku

$ heroku config:set DJANGO_SETTINGS_MODULE=mysite.production_settings

將專案上傳到 Heroku

$ git push heroku master

網站初始化

$ heroku ps:scale web=1
$ heroku run python mysite/manage.py migrate
$ heroku run python mysite/manage.py createsuperuser

試試看成功了沒

$ heroku open

Thanks for listening.

References

兩堂課帶你入門 Django

By oneone

兩堂課帶你入門 Django

【SIRLA 2021 對外課程】雖然寫著兩堂課,但其實是(目標)兩堂課帶你入門

  • 167