Python 3 Tutorial 第九堂(1)ORM 操作


在〈Python 3 Tutorial 第八堂(2)建立 App 與模型〉中,已經撰寫了模型程式碼,並且利用 Django 的遷移(Migration)功能,自動建立了資料庫中的相關表格,接下來,我們就來操作模型與資料庫吧!

查詢全部資料

你可以鍵入 python3.5 manage.py shell 指令,這會設定 DJANGO_SETTINGS_MODULE 環境變數,讓你可以取用 Django 的 Python 模組,然後進入 Python 互動環境,在當中體驗一些 API 的使用。

ORM 操作

一開始從 polls.models 模組中,匯入了 QuestionChoice 類別,若想查詢全部的「問題」或「選項」,可以使用 Question.objects.all()Choice.objects.all(),也就是在類別名稱之後,接下 objects.all()

可以看到,你不用撰寫任何 SQL,Django 會自動幫你轉換對應的 SQL,取得結果然後包裝為物件,你不用自行進行物件與關聯式資料庫之間的對應,這樣的技術稱之為 ORM(Object-Relational Mapping),對於應用程式快速開發時非常便利,當然,目前「問題」與「選項」都沒有任何資訊,因此傳回空 list

資料儲存、欄位查詢與更新

接著在資料庫進行資料的儲存,直接來看看如何儲存「問題」:

>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())
>>> q.save()
>>> q.id
1
>>> q.question_text
"What's new?"
>>> q.pub_date
datetime.datetime(2016, 3, 5, 9, 18, 10, 991796, tzinfo=<UTC>)
>>> q.question_text = "What's up?"
>>> q.save()
>>> Question.objects.all()
[<Question: What's up?>]
>>> 

因為 Question 在儲存時,必須提供時間資訊,因此從 django.utils 模組中匯入了 timezone,要儲存一個「問題」,只要建立 Question 實例,並呼叫其 save() 就可以了,至於查詢或更新相關欄位,也只是對屬性做操作。

特定條件查詢

那麼,如果有多個「問題」,想要進行條件過濾呢?可以使用 filter 函式,例如:

>>> Question.objects.filter(id=1)
[<Question: What's up?>]
>>> Question.objects.filter(question_text__startswith='What')
[<Question: What's up?>]
>>> Question.objects.filter(id=2)
[]
>>> Question.objects.filter(question_text__startswith='What')
[<Question: What's up?>]
>>> 

可以看到,filter 函式會以 list 傳回符合條件的資料,如果你只想取回一筆資料,也可以使用 get,不過,若查詢的條件不存在,get 會引發 DoesNotExist 的錯誤,例如:

>>> Question.objects.get(pub_date__year=timezone.now().year)
<Question: What's up?>
>>> Question.objects.get(id=1)
<Question: What's up?>
>>> Question.objects.get(id=2)
Traceback (most recent call last):
略...
polls.models.DoesNotExist: Question matching query does not exist.
>>> Question.objects.get(pk=1)
<Question: What's up?>
>>> 

在查詢主鍵時,使用 get(id=1)get(pk=1) 都可以。

建立關聯與刪除資料

一個「問題」會有多個「選項」,來看看怎麼建立兩者之間的關聯:

>>> q = Question.objects.get(pk=1)
>>> q.choice_set.all()
[]
>>> q.choice_set.create(choice_text='Not much', votes=0)
<Choice: Not much>
>>> q.choice_set.create(choice_text='The sky', votes=0)
<Choice: The sky>
>>> c = q.choice_set.create(choice_text='Just hacking again', votes=0)
>>> c.question
<Question: What's up?>
>>> q.choice_set.all()
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
>>> q.choice_set.count()
3
>>> Choice.objects.filter(question__pub_date__year=timezone.now().year)
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
>>> c = q.choice_set.filter(choice_text__startswith='Just hacking')
>>> c.delete()
(1, {'polls.Choice': 1})
>>>

這些操作都不太需要多做解釋,若想進一步瞭解更多這類操作,可以參考〈Database API reference〉。