Django

Lecturer:Yan

2020 / 4 / 5

Models

  • Introduction of model.

  • Basic OOP

  • Create an application.

  • Create a blog post model.

  • Create tables.

  • Django admin

Outline

Introduction of Model

Models

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

...

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

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

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

Basic OOP

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/

或是現在叫我再講一次

Lab 1 - Class

建立一個叫 cat 的 class

  • attribute:姓名、年齡
  • method:會叫

Lab 1 - Class

little_white = Cat('你幫那隻貓取的名字',3)
little_white.purr()
print(little_white.name)
你設定的叫聲
你幫那隻貓取的名字

建立一個叫小白的 Object

希望出現的結果:

class Cat:
	# attribute
	def __init__(self,name,age):
		self.name = name
		self.age = age

	# method
	def purr(self):
		print('meow')

little_white = Cat('little_white',3) # 實例化 class

little_white.purr() # 呼叫 class 的 method
print(little_white.name) # 呼叫 class 的 attribute

Lab - 1 完整程式碼

  • 繼承是指,從原先有的 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')

繼承的完整程式碼

Lab 2 - Inheritance

建立一個叫 kitten 的 class 並繼承剛剛寫的 Cat

  • attribute:名字、年齡、顏色
  • method:會叫、會抓
class kitten(Cat):
    
    def __init__(self,name,age,color):
    	super().__init__(name,age)
        # 新增 attribute - 花色
        self.color = color
    
    def scarch(self):
      	# 新增 method - 抓
        print('sofa gg')

little_black = kitten('little_black',6,black) # 建立 object

little_black.purr() # 呼叫父類別的 method
print(little_black.name) # 呼叫父類別的 attribute

little_black.scarch() # 呼叫子類別的 method
print(little_black.color) # 呼叫子類別的 attribute

Lab - 2 子類別寫法

# 父類別
class Cat:
  	# attribute
    def __init__(self,name,age):
        self.name = name
        self.age = age
    
    # method
    def purr(self):
        print('meow')

# 建立一個叫 kitten 的 class 並繼承剛剛寫的 Cat
class kitten(Cat):
    def __init__(self,name,age,color):
    	super().__init__(name,age)
        # 新增 attribute - 花色
        self.color = color
    
    def scarch(self):
      	# 新增 method - 抓
        print('sofa gg')

little_black = kitten('little_black',6,black) # 建立 object

little_black.purr() # 呼叫父類別的 method
print(little_black.name) # 呼叫父類別的 attribute

little_black.scarch() # 呼叫子類別的 method
print(little_black.color) # 呼叫子類別的 attribute

Lab - 2 完整程式碼

Creat an application

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

進到上次建立的虛擬環境中

$ cd 到上次建立的資料夾
$ venv\Scripts\activate
$ cd 到上次建立的資料夾
$ source venv/bin/activate

for Windows

for Mac

如果你不小心刪掉上次的 venv 了

不用翻之前的 slide,你要的都在這~

$ cd 到你要建虛擬環境的資料夾
$ python -m venv 你想取的名字

$ source venv/bin/activate #用 windows 的請去掉 source

$ pip install django
$ django-admin startproject mysite

如果你不小心刪掉上次的 project

$ django-admin startproject mysite

新建 app

$ python manage.py startapp blog

blog 是可以換成你想取的 app 名稱的

告訴 Django 需要管理的 app

修改 mysite/settings.py

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'trips',
    # 新增
    'blog',
)

記得是要加入你剛剛建立的 app 名稱

Create a blog post model

定義 Models 的 object

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

$ 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

Django Admin ?

  • Django 內建的一個 App
  • 經設定可用來管理後台
$ python manage.py createsuperuser

要使用 Django 的管理後台,

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

接著就照著指示建立好帳號

# blog/admin.py
from django.contrib import admin
from .models import Post


admin.site.register(Post)

還要讓 Django 知道,

有哪些 Model 需要管理後台。

$ python manage.py runserver

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

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

登入後畫面

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

Thanks for listening.

References

References

Django - Models

By oneone

Django - Models

SIRLA 2020 Django Tutorial

  • 191