iT邦幫忙

2024 iThome 鐵人賽

DAY 13
1
Python

Python 錦囊密技系列 第 13

【Python錦囊㊙️技13】OOP 實作(3) -- 資料庫ORM

  • 分享至 

  • xImage
  •  

前言

上一篇以遊戲為例說明OOP開發方式,這次則以OOP開發資料庫應用程式。

Python有許多資料庫程式開發套件,其中Django、SQLAlchemy最為盛行,Django是一網頁架構套件,兼具資料庫存取模組,而SQLAlchemy則只聚焦在資料庫存取,可搭配其他網頁架構套件開發,例如Flask、FastAPI。

關聯式資料庫的存取方式為SQL語言,程式設計師須額外學習SQL,因此,有人提出ORM(Object Relational Mapping)技術,以類別(Class)對應資料表(Table),藉由操作物件的方式自動生成並執行SQL,對資料庫進行新增/更正/刪除/查詢(CRUD)動作,優點包括:

  1. 不需額外學習SQL語言。
  2. 可以模組化資料庫存取程式。

缺點包括:

  1. 效能較差:操作物件的動作要先轉換成SQL,再對資料庫進行CRUD。
  2. 除錯較困難:生成SQL是否正確或具備效率,需額外確認及修正。

實作

以Django為例,使用ORM步驟如下:

  1. 建立類別(Class)對應資料表(Table)。
  2. 建立空白的資料庫。
  3. 生成並執行Migration plan,產生資料表結構(Schema)。
  4. 撰寫程式,創建及操作物件,以對資料庫進行新增/更正/刪除/查詢(CRUD)。

先安裝Django套件,指令如下:

pip install django -U

範例1. Django最簡程式,程式目錄為mysite。

  1. 建立新專案mysite:執行後會建立空白的SQLite資料庫db.sqlite3。
django-admin startproject mysite
  1. 切換至專案目錄mysite,並啟動server。
cd mysite
python manage.py runserver
  1. 測試:開啟瀏覽器,輸入 http://localhost:8000/

  2. 執行結果:
    https://ithelp.ithome.com.tw/upload/images/20240926/200019769qJ1UwWz4z.png

範例2. 延續範例1,建立模型及資料表。

  1. 生成Migration plan:會在資料庫內生成一堆的資料表,包括使用者、權限控管及管理者工作日誌...等資料表,最重要的是django_migrations資料表,它記錄模型與資料表同步的歷史。
python manage.py migrate
  1. 建立app:一個專案內可以有多個App,以下列指令建立polls app。
python manage.py startapp polls
  1. 將polls app納入專案設定檔:修改mysite\mysite\settings.py,加入polls.apps.PollsConfig。
INSTALLED_APPS = [
    "polls.apps.PollsConfig",
    "django.contrib.admin",
  1. 建立模型:每個類別均繼承Django的models.Model,類別內定義欄位,欄位型態可參閱【Django Model field reference】,程式名稱為mysite\polls\models.py。以實體關聯圖(Entity Relationship Diagram, ERD)表示一對多關係,即一個問題(Question)對應多個答案選項(Choice)。
    https://ithelp.ithome.com.tw/upload/images/20240927/20001976UxME0yEdOt.png
from django.db import models

# 問題
class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField("date published")

# 答案選項
class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)
  1. 建立Migration plan的記錄檔:會比較app的models.py與資料庫的差異,生成同步所需的程式碼。
python manage.py makemigrations polls
  1. 執行結果:產生0001_initial.py檔案,包括差異的內容。
Migrations for 'polls':
  polls\migrations\0001_initial.py
    + Create model Question
    + Create model Choice
  1. 同步測試:指定同步檔案的代號(0001),此步驟非必要,只是查看SQL指令。
python manage.py sqlmigrate polls 0001
  1. 執行結果:會顯示SQL指令。
BEGIN;
--
-- Create model Question
--
CREATE TABLE "polls_question" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "question_text" varchar(200) NOT NULL, "pub_date" datetime NOT NULL);
--
-- Create model Choice
--
CREATE TABLE "polls_choice" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "choice_text" varchar(200) NOT NULL, "votes" integer NOT NULL, "question_id" bigint NOT NULL REFERENCES "polls_question" ("id") DEFERRABLE INITIALLY DEFERRED);
CREATE INDEX "polls_choice_question_id_c5b4b260" ON "polls_choice" ("question_id");
COMMIT;
  1. 同步:系統會檢查資料庫的django_migrations資料表,檢視上次同步到哪一個步驟,以下指令會執行全部尚未被執行的計劃。
python manage.py migrate
  1. 執行結果:查看mysite\db.sqlite3,可以看到polls_question、polls_choice資料表,筆者使用【SQLiteSpy】工具軟體。
    https://ithelp.ithome.com.tw/upload/images/20240926/20001976Zitr2yw1Oq.png

資料存取(CRUD)

目前只有空白資料表,沒有資料,我們可以利用指令對資料庫進行新增/更正/刪除/查詢(CRUD),當然,正常是應該使用網頁,不過本文是介紹ORM,就先省略了。

範例3. 利用Django shell操作資料庫。

  1. 先執行Django shell,會出現互動式環境。
python manage.py shell
  1. 查詢問題。
from polls.models import Choice, Question
Question.objects.all()
  1. 執行結果:沒有資料。
<QuerySet []>
  1. 新增問題。
from django.utils import timezone
q = Question(question_text="What's new president?", pub_date=timezone.now())
q.save()
q.id
  1. 執行結果:得到新增問題資料的id=1,再查看資料,確實有一筆資料。
    https://ithelp.ithome.com.tw/upload/images/20240926/20001976bRbRdS41HF.png

  2. 但時間是格林威治時區,可修改mysite\settings.py的TIME_ZONE為Asia/Taipei及USE_TZ = False,再重新執行python manage.py shell。

  3. 修改問題。

q = Question.objects.first()
q.pub_date=timezone.now()
q.save()
  1. 執行結果:得到正確的時間。

  2. 刪除問題。

q.delete()
  1. 執行結果:再使用 Question.objects.all()查詢,已無該筆資料。

  2. 可設定篩選資料查詢。

Question.objects.filter(id=6) # 查id=6,可能傳回多筆(list)
Question.objects.frist()      # 傳回第一筆
Question.objects.get(pk=6)    # 傳回主鍵(primary key)=6的那一筆
  1. 新增答案:question屬性值須為Question物件,而非id。
c1 = Choice(question = q, choice_text = '川普', votes = 1)
c1.save()
c2 = Choice(question = q, choice_text = '賀錦麗', votes = 2)
c2.save()
  1. 執行結果:
    https://ithelp.ithome.com.tw/upload/images/20240926/20001976Ebzvy9OkAq.png

測試

讀者可以自GitHub複製src\13\mysite資料夾。

  1. 執行以下指令啟動Server:
python manage.py runserver
  1. 在瀏覽器輸入URL即可。
http://localhost:8000/
  1. 也可以刪除db.sqlite3,執行以下指令重建資料庫。
python manage.py makemigrations
python manage.py migrate

結語

以上就是ORM的操作方式,完全以OOP精神開發資料庫應用程式,從上一篇的遊戲開發及本篇,可以看到如何從分析、設計到程式撰寫連貫的脈絡。

Django的操作指令雖然繁瑣,與C# Entity Framework、Rust套件...等都是相似的作法,熟悉Migration Plan有助於ORM觀念的理解,且在佈署至測試及上線環境上也較方便,只要依照測試步驟3,就可以一次建立好所有資料表。

下一篇會討論資料庫設計(Schema design),並完成網頁設計。

本系列的程式碼會統一放在GitHub,本篇的程式放在src/13資料夾,歡迎讀者下載測試,如有錯誤或疏漏,請不吝指正。


上一篇
【Python錦囊㊙️技12】OOP 實作(2) -- 遊戲開發
下一篇
【Python錦囊㊙️技14】資料庫設計準則 (Schema design)
系列文
Python 錦囊密技30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言