投稿日:2020年10月24日
Djangoにはランダムにレコードを取得する方法が用意されています。 この方法を知っていると意外と役に立つ場面が多いので使い方と注意点についてメモしておきます。
Djangoにはランダムにレコードを取得する方法が用意されています。
この方法を知っていると意外と役に立つ場面が多いので使い方と注意点についてメモしておきます。
DjangoのQuerySetクラスのorder_by()関数は指定されたフィールドの値ごとに並び替えるQuerySetを取得します。
order_by()に渡す引数として?を指定することでランダムなQuerySetを取得することができます。
例えばBlogPageというdjango.db.models.Modelを継承したModelクラスがあったとすると以下のような記述でランダムに並んだレコードを取得できます。
pages = BlogPage.objects.order_by("?")
ランダムなレコード取得は非常に便利なのですが、2つほど注意する点があります。
以下にその注意点について解説しておきます。
ランダムなレコードの並び変えのQuerySetの評価タイミングについて少し注意しなければいけません。例えば以下のようなスクリプトを作成するとします。
from blog.models import BlogPage
pages = BlogPage.objects.order_by("?")[:10]
print(pages[0].id == pages[0].id)
「何言ってるんや?wwwこいつ?www」
って感じのスクリプトです。
「Trueが返されるに決まってるわwww逝ってよしwww」
と思うかもしれません。
しかし、実際に実行してみると...
$ python manage.py shell < sample.py
False
以外にも!
結果はFalseになりました!
実はQuerySetの並び替えは値の取得のたびに評価されるのです。
これを理解していないと、DBへの無駄なクエリの生成や、思わぬバグを生み出す原因になってしまいます!
解決方法は以外と簡単でQuerySet型から配列にキャストしてあげれば良いだけです!
from blog.models import BlogPage
pages = BlogPage.objects.order_by("?")[:10]
pages = list(pages) # 配列にキャスト
print(pages[0].id == pages[0].id)
$ python manage.py shell < sample.py
False
ランダムなレコードの取得をする際には、この挙動について常に気を向けておくべきですね。