[Django] QuerySetメソッド完全ガイド



## はじめに
Djangoフレームワークを使用している際、データベース操作の中心となるのが`QuerySet`です。
`QuerySet`は、データベースからデータを取得し、加工、操作するための強力なツールです。
本記事では、`QuerySet`に用意されている多種多様なメソッドを詳しく解説します。
`QuerySet`の理解を深め、効率的で効果的なデータベース操作ができるようになりましょう。

## QuerySetとは
`QuerySet`は、DjangoのデータベースAPIの核となる部分で、データベースから取得したオブジェクトの集合を表します。
`QuerySet`は遅延評価されるため、必要なときにのみデータベースにアクセスする効率的なデザインが特徴です。
これにより、パフォーマンスが最適化され、無駄なデータベースクエリの発行が防がれます。

## 基本メソッド

### 1. `all()`
`all()`メソッドは、モデルのすべてのレコードを取得するために使用されます。最もシンプルで基本的なメソッドです。

```python
# 例: すべてのUserオブジェクトを取得
users = User.objects.all()
```

### 2. `filter()`
`filter()`メソッドは、指定した条件に一致するオブジェクトのみを含むクエリセットを返します。複数の条件をチェーンして使用でき、AND条件となります。

```python
# 例: 年齢が30以上のユーザーを取得
users = User.objects.filter(age__gte=30)
```

### 3. `exclude()`
`exclude()`メソッドは、指定した条件に一致しないオブジェクトを含むクエリセットを返します。`filter()`の逆の動作をします。

```python
# 例: 年齢が30未満のユーザーを除外
users = User.objects.exclude(age__lt=30)
```

### 4. `get()`
`get()`メソッドは、指定した条件に一致する1つのオブジェクトを返します。条件に一致するオブジェクトが複数存在する場合や存在しない場合は例外が発生します。

```python
# 例: 特定のIDを持つユーザーを取得
user = User.objects.get(id=1)
```

### 5. `order_by()`
`order_by()`メソッドは、指定したフィールドに基づいて結果を並べ替えます。デフォルトでは昇順ですが、フィールド名の前に`-`を付けると降順になります。

```python
# 例: 名前で昇順、年齢で降順に並べ替え
users = User.objects.order_by('name', '-age')
```

## 集計メソッド

### 6. `annotate()`
`annotate()`メソッドは、各オブジェクトに追加の集計データを付加します。集計関数を使用して、新しいフィールドをクエリセットに追加します。

```python
# 例: 各ユーザーが投稿した記事の数をカウント
users = User.objects.annotate(article_count=Count('article'))
```

### 7. `aggregate()`
`aggregate()`メソッドは、全体の集計を行い、その結果を辞書形式で返します。集計結果は1つの値にまとめられます。

```python
# 例: 全ユーザーの平均年齢を計算
average_age = User.objects.aggregate(Avg('age'))
```

## 高度なクエリメソッド

### 8. `select_related()`
`select_related()`メソッドは、外部キーで関連付けられたオブジェクトを一度に取得し、データベースクエリを最適化します。リレーションが1対1または多対1の場合に効果的です。

```python
# 例: 記事と著者情報を一度に取得
articles = Article.objects.select_related('author')
```

### 9. `prefetch_related()`
`prefetch_related()`メソッドは、多対多やリバースリレーションの最適化に使用され、複数のクエリをまとめて発行します。

```python
# 例: 記事とそれに関連するタグ情報を取得
articles = Article.objects.prefetch_related('tags')
```

### 10. `distinct()`
`distinct()`メソッドは、重複するレコードを排除し、一意の結果を返します。特定のフィールドで重複を排除することも可能です。

```python
# 例: ユニークな名前を持つユーザーを取得
users = User.objects.distinct('name')
```

## クエリセットの評価

### 11. `count()`
`count()`メソッドは、クエリセットに含まれるオブジェクトの数を取得します。クエリセット全体を評価するわけではないため、効率的です。

```python
# 例: 全ユーザーの数を取得
user_count = User.objects.count()
```

### 12. `exists()`
`exists()`メソッドは、クエリセットに少なくとも1つのオブジェクトが存在するかどうかを確認します。結果はブール値で返されます。

```python
# 例: 特定の名前を持つユーザーが存在するか確認
is_exists = User.objects.filter(name='John').exists()
```

## データ操作メソッド

### 13. `create()`
`create()`メソッドは、新しいオブジェクトを作成し、データベースに保存します。オブジェクトを作成して保存するまでの一連の操作を1ステップで行えます。

```python
# 例: 新しいユーザーを作成
user = User.objects.create(name='John', age=30)
```

### 14. `bulk_create()`
`bulk_create()`メソッドは、複数のオブジェクトを一度に作成し、データベースに保存します。大量データの挿入に適しています。

```python
# 例: 複数のユーザーを一括作成
users = User.objects.bulk_create([
    User(name='John', age=30),
    User(name='Jane', age=25),
])
```

### 15. `update()`
`update()`メソッドは、クエリセット内のオブジェクトを一括で更新します。複数のフィールドを同時に更新することも可能です。

```python
# 例: 全ユーザーの年齢を1つ増加
User.objects.update(age=F('age') + 1)
```

### 16. `delete()`
`delete()`メソッドは、クエリセット内のオブジェクトを削除します。削除後はクエリセットは空になります。

```python
# 例: 特定の年齢以下のユーザーを削除
User.objects.filter(age__lt=20).delete()
```


### 17. `first()`
`first()`メソッドは、クエリセットの最初のオブジェクトを返します。オブジェクトが存在しない場合は`None`を返します。

```python
# 例: 最初のユーザーを取得
user = User.objects.first()
```

### 18. `last()`
`last()`メソッドは、クエリセットの最後のオブジェクトを返します。オブジェクトが存在しない場合は`None`を返します。

```python
# 例: 最後のユーザーを取得
user = User.objects.last()
```

### 19. `reverse()`
`reverse()`メソッドは、クエリセットの並び順を逆にします。たとえば、デフォルトで降順に並んでいるものを昇順にする場合に便利です。

```python
# 例: ユーザーを逆順に取得
users = User.objects.all().reverse()
```

### 20. `defer()`
`defer()`メソッドは、特定のフィールドの取得を遅延させます。これにより、最初に取得されるデータの量を減らし、パフォーマンスを向上させることができます。

```python
# 例: 名前フィールドを除くすべてを取得
users = User.objects.defer('name')
```

### 21. `only()`
`only()`メソッドは、指定されたフィールドのみを取得します。これにより、不要なデータの取得を避け、効率的なデータベース操作が可能になります。

```python
# 例: 名前と年齢のみを取得
users = User.objects.only('name', 'age')
```

### 22. `select_for_update()`
`select_for_update()`メソッドは、データベースの行をロックして更新を行う際に使用されます。これにより、同時実行性制御が必要なシナリオで安全なデータ操作が可能になります。

```python
# 例: トランザクション内でユーザーをロック
with transaction.atomic():
    user = User.objects.select_for_update().get(id=1)
```

### 23. `update_or_create()`
`update_or_create()`メソッドは、指定した条件でオブジェクトを検索し、存在すれば更新し、存在しなければ新規作成します。

```python
# 例: ユーザーが存在しなければ作成し、存在すれば更新
user, created = User.objects.update_or_create(
    name='John',
    defaults={'age': 30}

    
)
```

### 24. `get_or_create()`
`get_or_create()`メソッドは、指定した条件でオブジェクトを検索し、存在しなければ新規作成します。データがないときにデフォルト値を設定するのに便利です。

```python
# 例: ユーザーが存在しなければ作成
user, created = User.objects.get_or_create(name='John', defaults={'age': 30})
```

### 25. `bulk_update()`
`bulk_update()`メソッドは、複数のオブジェクトのフィールドを一括で更新します。このメソッドはパフォーマンスを重視する場合に有効です。

```python
# 例: 複数のユーザーの年齢を一括更新
User.objects.bulk_update(users, ['age'])
```


### 26. `earliest()`
`earliest()`メソッドは、指定したフィールドの最も早い（最小の）値を持つオブジェクトを返します。

```python
# 例: 最も早い登録日のユーザーを取得
user = User.objects.earliest('date_joined')
```

### 27. `latest()`
`latest()`メソッドは、指定したフィールドの最も遅い（最大の）値を持つオブジェクトを返します。

```python
# 例: 最も遅い登録日のユーザーを取得
user = User.objects.latest('date_joined')
```

### 28. `in_bulk()`
`in_bulk()`メソッドは、主キーのリストを受け取り、それに対応するオブジェクトを辞書形式で返します。

```python
# 例: 特定のIDのユーザーを辞書形式で取得
users = User.objects.in_bulk([1, 2, 3])
```

### 29. `iterator()`
`iterator()`メソッドは、メモリ効率を高めるためにクエリセットを1つずつ取り出すイテレータを返します。

```python
# 例: ユーザーをイテレータで1つずつ処理
for user in User.objects.iterator():
    print(user.name)
```

### 30. `extra()`
`extra()`メソッドは、SQLクエリをカスタマイズするために使用されます。特定のSQL句を追加したい場合に有効ですが、後述の`Func`や`RawSQL`といった代替手段の使用が推奨されています。

```python
# 例: 生SQLを追加してクエリをカスタマイズ
users = User.objects.extra(where=["age > 30"])
```

### 31. `raw()`
`raw()`メソッドは、生のSQLクエリを実行し、クエリセットのように使用できる結果を返します。直接SQLを記述したい場合に便利です。

```python
# 例: 生SQLでユーザーを取得
users = User.objects.raw('SELECT * FROM myapp_user WHERE age > %s', [30])
```

### 32. `union()`
`union()`メソッドは、複数のクエリセットの結果を結合し、重複を排除した結果を返します。

```python
# 例: 2つのクエリセットを結合
qs1 = User.objects.filter(age__lt=30)
qs2 = User.objects.filter(name__startswith='J')
combined = qs1.union(qs2)
```

### 33. `intersection()`
`intersection()`メソッドは、複数のクエリセットの共通の結果を返します。

```python
# 例: 2つのクエリセットの共通のユーザーを取得
common_users = qs1.intersection(qs2)
```

### 34. `difference()`
`difference()`メソッドは、クエリセットの差集合を返します。

```python
# 例: 1つ目のクエリセットに存在し、2つ目には存在しないユーザーを取得
diff_users = qs1.difference(qs2)
```

### 35. `select_for_update()`
`select_for_update()`メソッドは、トランザクション内で行ロックを取得するために使用され、データの競合を防ぎます。

```python
# 例: トランザクション内で特定のユーザーをロック
with transaction.atomic():
    user = User.objects.select_for_update().get(id=1)
```

## さいごに
これらのメソッドを活用することで、Djangoでのデータベース操作をさらに高度に制御することができます。
どのメソッドを使うかは、システムの要件に応じて選択してください。

# 参考
https://docs.djangoproject.com/en/5.1/ref/models/querysets/