知識の枝

"All is well"

Django モデルの有無でif分岐する方法

約83日前 2021年8月6日20:14
デジタル
Django

改訂履歴


2021/8/6 投稿

1. 背景


Djangoを使った開発中に覚えたことを備忘録として残します。

今回はモデルのオブジェクトがあるかないかで処理を分岐する方法を解説します。


2. ゴール


モデルのオブジェクトが無かった場合にのみ実行するコードを書く。


3. はじめに


今回やりたいことはタイトルのまんまです。

if文で分岐する際に「条件に合うモデルがあるかないか」で処理を分けようと思います。


どんな場面で使えそうでしょうか?

例えば、「ゲームアプリのスキルのクールダウン」を管理する際に使えそうです。

スキルを使ったら30秒間再使用不可、使用しようとすると「クールダウン中です」とメッセージが出るようにしたいと思います。

次項で具体的に実装方法を解説します。



4. exists()を使う


先に今回のキーワードを共有します。

「exists()」です。

Model.objects.filter(〇〇).exists() のように書きます。

上記の例では、”条件〇〇”に合うモデルが存在したら「True」を返し、無ければ「False」を返します。

そのままif文に組み込んで分岐することが可能です。
if Model.objects.filter(〇〇).exists():
print("モデルあり"
else:
print("モデル無し")
といった感じです。



ではゲームアプリのクールダウンを実装します。

「スキルモデル」とスキルをいつ使ったか記録する「スキル履歴モデル」を作成します。
【models.py】
# スキルモデル
class Skill(models.Model):
name = models.CharField(verbose_name='スキル名', max_length=10)
cool_down = PositiveIntegerField(verbose_name='クールダウン時間(sec)')

# スキル履歴モデル
class Record(models.Model):
skill = models.ForeignKey(Skill, verbose_name='スキル名', on_delete=models.CASCADE)
used_at = models.DateTimeField(verbose_name='いつ使ったか', default=timezone.now)

クールダウンの機能は下記のように実装したいと思います。
分かり易いようにスキルは「ファイア」、クールダウンは「30秒」とします。


①ファイアボタンをクリック。

②現在時刻から30秒前の時刻を計算し、その時刻以降にファイアが使われているか確認。

③使われている場合は「クールダウン中です」と表示。
 使われていない場合は「ファイア!」と表示。


この流れでいきましょう。


views.pyの中の処理を書きます。
【views.py】
# 下記をインポートしておきましょう
from datetime import timedelta
from django.utils import timezone

”””中略”””
# ファイアボタンが押されたのでそれを受け取りました。
used_skill = "ファイア"

#ファイアモデルを取得
skill = Skill.objects.get(name=used_skill)

# 現在時刻からファイアのクールダウンを差し引く
now-cd = timezone.now() - timedelta(seconds=skill.cool_down)

# クールダウン中かどうかチェックします
if Record.objects.filter(skill=skill, used_at__gte=now-cd).exists():
# クールダウン中だった場合
print("クールダウン中です")
else:
# クールダウン中でなかった場合
print("ファイア!")
Record.objects.create(skill=skill) #使った履歴を残す
こんな感じで実装できます。

クールダウン中かどうかチェックする場面で「exists()」を使っています。

下記のフィルターでスキルを「ファイア」に絞り込みつつ、30秒以内にファイアを使用した履歴があるか確認しています。
filter(skill=skill, used_at__gte=now-cd)

そしてexists()でTrueなら「クールダウン中」を表示し、そうでないならスキルが発動します。

スキルと使ったらしっかり履歴を残します。
Record.objects.create(skill=skill)
「used_at」カラムはdefaultで現在時刻が入るのでcreateの引数には渡していません。
used_at = models.DateTimeField(verbose_name='いつ使ったか', default=timezone.now)

exist()の使用例は以上です。



5. さいごに


使う場面は限られるかもしれませんが、exists()を使う機会はあると思います。

覚えておいて損はないでしょう!

あと「exist()」ではなく「exists()」です!
「s」をよく忘れるので気を付けましょう。