[前回] Django+Reactで学ぶプログラミング基礎(9): Djangoチュートリアル(投票アプリその4-2)
はじめに
Django公式チュートリアル、その5-1です。
前回は、アプリを汎用ビューに書き換えました。
今回は、アプリのテストフェーズに入ります。
Djangoアプリ作成(その5-1): 投票(poll)アプリ
今回の内容
- Python対話シェルで、APIを使用し動作確認
Djangoが提供するAPIで遊んでみる
※ チュートリアル その2の内容をここに移動しました。
- Python対話シェルを起動し、Djangoが提供するAPIの動作確認
- Pythonを
manage.py
経由で実行する理由-
manage.py
に設定されているDJANGO_SETTINGS_MODULE
環境変数を使用するため
-
- Pythonを
C:\kanban\pollsite>..\venv\.venv\Scripts\activate
(venv) C:\kanban\pollsite>python manage.py shell
- モデルクラス二つをインポート
>>> from polls.models import Choice, Question
- 質問事項のリストを確認
>>> Question.objects.all()
<QuerySet [<Question: Question object (1)>, <Question: Question object (2)>, <Question: Question
object (3)>, <Question: Question object (4)>, <Question: Question object (5)>, <Question: Question object (6)>]>
- 新しい質問を作成し、保存
- デフォルトでタイムゾーンが有効になっている
-
pub_date
フィールドにはdatetime with tzinfo
データ型を指定 -
timezone.now()
関数を使用し、現在時刻を取得(datetime.datetime.now()
関数ではなく)
-
- デフォルトでタイムゾーンが有効になっている
>>> from django.utils import timezone
>>> q = Question(question_text="気持ちはいかがでしょうか?", pub_date=timezone.now())
>>> q.save()
- 質問
ID
を確認
>>> q.id
7
- Python属性を使用し、モデルフィールド値にアクセス
>>> q.question_text
'気持ちはいかがでしょうか?'
>>> q.pub_date
datetime.datetime(2022, 6, 7, 23, 20, 34, 394580, tzinfo=datetime.timezone.utc)
- 属性を変更することで、フィールド値を変更し、保存
>>> q.question_text = "今日の予定は?"
>>> q.save()
- 質問事項に新しい質問が追加されたことを確認
>>> Question.objects.all()
<QuerySet [<Question: Question object (1)>, <Question: Question object (2)>, <Question: Question
object (3)>, <Question: Question object (4)>, <Question: Question object (5)>, <Question: Question object (6)>, <Question: Question object (7)>]>
- 質問オブジェクトの表現をわかりやすく修正
-
<Question: Question object (1)>
のような表現は可読性がない -
Question
モデルとChoice
モデルに__str__()
メソッドを追加 -
__str__()
メソッドによるオブジェクト表現は- Django自動生成の管理サイトでも使用される(対話シェルだけでなく)
-
polls/models.py
from django.db import models
class Question(models.Model):
# ...
def __str__(self):
return self.question_text
class Choice(models.Model):
# ...
def __str__(self):
return self.choice_text
- モデルクラスにクラスメソッドを追加
- 以下2点参照するためインポート
- Python標準モジュール
datetime
をインポート - Djangoタイムゾーン関連ユーティリティ
django.utils.timezone
をインポート
- Python標準モジュール
- 以下2点参照するためインポート
polls/models.py
import datetime
from django.db import models
from django.utils import timezone
class Question(models.Model):
# ...
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
-
polls/models.py
の変更を保存 - 新しいPython対話シェルを始める
>>> exit()
(venv) C:\kanban\pollsite>python manage.py shell
>>> from polls.models import Choice, Question
-
__str__()
メソッドが機能するか確認
>>> Question.objects.all()
<QuerySet [<Question: Djangoは難しいですか>, <Question: 難しいポイントは?>, <Question: 趣味は?>, <Question: 目標は?>, <Question: 幸せとは?>, <Question: 楽しいことは?>, <Question: 今日の予定は?>]>
- 検索APIで検索
- Djangoは、キーワード引数によって駆動される検索APIを提供
>>> Question.objects.filter(id=1)
<QuerySet [<Question: Djangoは難しいですか>]>
>>> Question.objects.filter(question_text__startswith='Django')
<QuerySet [<Question: Djangoは難しいですか>]>
- 今年に公開された質問一覧を取得
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.filter(pub_date__year=current_year)
<QuerySet [<Question: Djangoは難しいですか>, <Question: 難しいポイントは?>, <Question: 趣味は?>, <Question: 目標は?>, <Question: 幸せとは?>, <Question: 楽しいことは?>, <Question: 今日の予定は?>]>
- 存在しない
ID
をリクエストすると、例外発生
>>> Question.objects.get(id=10)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "C:\kanban\venv\.venv\lib\site-packages\django\db\models\manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "C:\kanban\venv\.venv\lib\site-packages\django\db\models\query.py", line 496, in get
raise self.model.DoesNotExist(
polls.models.Question.DoesNotExist: Question matching query does not exist.
- 主キーによる検索には、ショートカット
pk
を使用- 以下は`Question.objects.get(id=1)と同じ
>>> Question.objects.get(pk=1)
<Question: Djangoは難しいですか>
- 上記追加した、カスタムメソッド
was_published_recently
が機能するか確認
>>> q = Question.objects.get(pk=7)
>>> q.was_published_recently()
True
- 質問にいくつかの選択肢を与える
>>> q = Question.objects.get(pk=7)
- 質問に紐づく選択肢セットを確認、存在しない
>>> q.choice_set.all()
<QuerySet []>
- 選択肢を三つ作成
>>> q.choice_set.create(choice_text='はい', votes=0)
<Choice: はい>
>>> q.choice_set.create(choice_text='いいえ', votes=0)
<Choice: いいえ>
>>> c = q.choice_set.create(choice_text='どちらでもない', votes=0)
-
Choice
オブジェクトから、関連するQuestion
オブジェクトにAPIでアクセス可能
>>> c.question
<Question: 今日の予定は?>
-
Question
オブジェクトから、関連するChoice
オブジェクトにAPIでアクセス可能
>>> q.choice_set.all()
<QuerySet [<Choice: はい>, <Choice: いいえ>, <Choice: どちらでもない>]>
>>> q.choice_set.count()
3
- APIで、検索キーワード引数の形式
-
field__lookuptype=value
- 区切り文字は、二重下線
- 例えば、
pub_date
フィールドが今年となっている質問のすべての選択肢を検索question__pub_date__year
-
>>> Choice.objects.filter(question__pub_date__year=current_year)
<QuerySet [<Choice: 難しい>, <Choice: 難しくない>, <Choice: 旅行>, <Choice: 課題解決>, <Choice: 趣味>, <Choice: はい>, <Choice: いいえ>, <Choice: どちらでもない>]>
- 選択肢を削除
>>> c = q.choice_set.filter(choice_text__startswith='どちらでもない')
>>> c.delete()
(1, {'polls.Choice': 1})
おわりに
Djangoが提供するAPIを使用し、モデル操作や確認を行ってみました。
次回も続きます。お楽しみに。