見出し画像

【サンプルコード付き】Django モデル オブジェクトの取得方法-応用編-

今回の記事は先回の基礎編の続きです。少しマニアックな内容も解説するので、モデルよりデータを取り出す(オブジェクト取得)方法について理解が不十分と感じる方は、まずは基礎編をご参照ください。

1. よく使うクエリセットメソッド

先回の基礎編ではクエリセット について、all()、filter()メソッドについて解説しましたが、今回はその他のクエリセット を取得する上で便利なメソッドについて解説していきます。

前提モデルは以下とします。

models.py

from django.db import models
from django.contrib.auth.models import User

class Post(models.Model):
   title = models.CharField(max_length=255)
   author = models.ForeignKey(User, on_delete=models.CASCADE)
   body = models.TextField()
   price = models.PositiveIntegerField(blank=True, null=True)

def __str__(self):
    return self.title

1.1  exists()メソッド

>>> Post.objects.all().exists()
True
>>> Post.objects.filter(title__icontains='ruby').exists()
False

exists()メソッド条件に合うオブジェクトが存在するかどうかを、True(存在)/False(存在しない)で返します。

特にif文とセットで使われるので覚えておきましょう。ちなみに下記のような使い方をした際、existsを使うと若干処理が早くなるので覚えておきましょう。

if some_queryset.exists():  #処理速度上がるので推奨
   print("There is at least one object in some_queryset")
   
if some_queryset:
   print("There is at least one object in some_queryset")

1.2  count()メソッド

>>> Post.objects.all().count()
6
>>> Post.objects.filter(title__icontains='django').count()
2

count()メソッドオブジェクトの数をカウントします。

投稿記事の総数を数える時等に使います。

1.3  order_by()メソッド

>>> Post.objects.all().order_by('price') #昇順
<QuerySet [<Post: 三番目に高い記事>, <Post: 二番目に高い記事>, <Post: 一番高い記事>]>

>>> Post.objects.all().order_by('-price') #降順
<QuerySet [<Post: 一番高い記事>, <Post: 二番目に高い記事>, <Post: 三番目に高い記事>]>

order_by()メソッドオブジェクトをソートします。order_by('〇〇')は昇順、order_by('-〇〇')は降順を意味し、〇〇にはモデルフィールドを入力します。

上記の例ではpriceを基準に並び替えています。

1.4  exclude()メソッド

>>> Post.objects.filter(title__icontains='django')
<QuerySet [<Post: how to study django>, <Post: HOW TO STUDY DJANGO>]>

#除外あり
>>> Post.objects.filter(title__icontains='django')\
.exclude(title='HOW TO STUDY DJANGO')
<QuerySet [<Post: how to study django>]>

exclude()メソッド指定したオブジェクトを除外することができます。上記の例文でもわかるとおり、exclude()メソッド使うとオブジェクトの数が減っているのがわかると思います。

2. スライスを使ったオブジェクトの制限

前提モデルは以下とします。

models.py

from django.db import models
from django.contrib.auth.models import User

class Post(models.Model):
  title = models.CharField(max_length=255)
  author = models.ForeignKey(User, on_delete=models.CASCADE)
  body = models.TextField()
  price = models.PositiveIntegerField(blank=True, null=True)

def __str__(self):
   return self.title

早速サンプルコードを使いながらスライスの使い方について解説します。

>>> Post.objects.all()[:5] #0~4のインデックス
<QuerySet [<Post: テスト>, <Post: how to study django>,\ 
<Post: 二番目に高い記事>,<Post: 一番高い記事>, <Post: HOW TO STUDY DJANGO>]>

>>> Post.objects.all()[2:5] #2~4のインデックス
<QuerySet [<Post: 二番目に高い記事>, <Post: 一番高い記事>, <Post: HOW TO STUDY DJANGO>]>

>>> Post.objects.all()[::2] #偶数番目のインデックス
[<Post: テスト>, <Post: 二番目に高い記事>, <Post: HOW TO STUDY DJANGO>]

DjangoでもPython同様スライスを使うことができます。使い方はPythonとほぼ同じですが、Djangoでは[-1]のようにマイナスは使うことができません。

Djangoでスライスを使うことでオブジェクトの数を制限することができます。リストページ等でページネーションを設定する際に使用します。

使い方はPython同様、以下のように使います。

[start : stop : step]

[:5] = [0:5:1]  #0,1,2,3,4のインデックス
[2:5] = [2:5:1] #2,3,4のインデックス
[::2] = [0:0:2] #偶数のインデックス

・start:開始
・stop:終わり(stopのインデックス含まない)
・step:何個ごとに抽出するか(デフォルト=1)
※start、stopは0の時省略可、stepはデフォルトの時省略可

3. 単体のオブジェクトを作成・更新・削除

前提モデルは以下とします。

models.py

from django.db import models
from django.contrib.auth.models import User

class Post(models.Model):
    title = models.CharField(max_length=255)
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    body = models.TextField()
    price = models.PositiveIntegerField(blank=True, null=True)
    views = models.PositiveIntegerField(default=0)

def __str__(self):
    return self.title

3.1 作成

>>> author = User.objects.get(username='saito')
>>> post = Post(title='作成1', author=author, body='本文', price=300) #インスタンス作成
>>> post.save() #保存

>>> Post.objects.get(title='作成1') #データベースより取得(保存されていることを確認)
<Post: 作成1>

オブジェクト作成の手順は上記のようにモデルクラスのインスタンスを作成してから、save()メソッドで保存します。

1ステップで作成→保存まで完了させることもできます。

>>> Post.objects.create(title='作成2', author=author, body='本文', price=300)
<Post: 作成2>

上記のようにcreate()メソッドを使えば、作成→保存まで1ステップで対応可能です。

◆オブジェクトが存在すれば取得/存在しなければ作成するメソッド

>>> User.objects.get_or_create(username='tanaka')
(<User: tanaka>, True) #Trueはtanakaユーザーが作成されたという意味

get_or_create()メソッド は、オブジェクトが存在する場合オブジェクトを取得(get)し、オブジェクトが存在しない場合オブジェクトを作成(create)します。

オブジェクトが作成される場合はTrue、オブジェクトがすでに存在する場合はFalseとなります。

3.2 更新

>>> post = Post.objects.get(title='作成1')
>>> post.title = '作成1-更新'
>>> post.save()

>>> Post.objects.get(title='作成1-更新') #更新されていることを確認
<Post: 作成1-更新>

オブジェクトの更新は一度オブジェクトを取得し値を変更してから、save()メソッドで保存します。

1ステップで変更→保存まで完了させることもできます。

Post.objects.filter(title='作成1').update(title='作成1-更新')

上記のようにupdateメソッドを使いましょう。

ただし一点注意が必要です。

クエリセット でなければupdate()メソッドは使えないので、get()メソッド(単体オブジェクト)ではなくfilter()メソッド(クエリセット)を使いましょう。

◆F関数と更新

#F関数使わない更新
>>> post = Post.objects.get(pk=1)
>>> post.views += 1
>>> post.save()

#F関数使う更新
>>> from django.db.models import F
>>> post = Post.objects.get(pk=1)
>>> post.views = F('views') + 1
>>> post.save()

viewsをカウントアップする例で解説していきます。

F関数を使うことでDBへのアクセス回数を減らすことができます。通常F関数を使わない場合、値の取得→値の更新と2回DBにアクセスしますが、F関数を使用する場合、DB内の値をpythonが受け取らずにDB側で直接更新してくれので1回のみのDBアクセスで済みます。

使用方法はF('フィールド名')とすればOKです。

UXを考慮する上でもかなり使える処理のため、ぜひマスターしましょう。

3.3 削除

>>> Post.objects.get(title='作成1').delete()

>>> Post.objects.get(title='作成1') #削除されていることを確認
blogapp.models.Post.DoesNotExist: Post matching query does not exist.

オブジェクトの削除は上記のようにdelete()メソッドで実行できます。

4. 最後に

いかがでしたか。

今回は、オブジェクト取得方法の応用編として少しマニアックだが知っていると便利なメソッドについて解説しました。

今回紹介したメソッドの他にも色々なメソッドがあるので、一度公式ドキュメントをみたり、シェルを使ったりして確認してみてください。

次回はMVTの"T"の部分"テンプレート"について解説するのでお楽しみに!

この記事が気に入ったらサポートをしてみませんか?