DjangoのモデルでQuerySetAPIの利用方法(基本)
DjangoのモデルでQuerySetのAPI
すぐに忘れてしまうので、モデルを利用したクエリ処理をを備忘録としてまとめておく
前提となるモデル
from django.db import models
class Monster ( models.Model ) :
class Meta:
db_table = "monster"
TYPE_CHOICES = (
(1, "炎属性"),
(2, "水属性"),
(3, "闇属性"),
)
name = models.CharField(
max_length=100
)
hp = models.IntegerField(
default=0
)
mp = models.IntegerField(
default=0
)
type = models.IntegerField(
choices=TYPE_CHOICES
)
birthday = models.DateField(
verbose_name="birthday",
)
def __str__(self):
return self.name
fixturesの作成
初期データを作成します
[
{
"model": "study.monster",
"pk": 1,
"fields": {
"name": "FireDragon",
"hp": 40,
"mp": 20,
"type" : 1,
"birthday": "2000-05-12"
}
},
{
"model": "study.monster",
"pk": 2,
"fields": {
"name": "IceDragon",
"hp": 30,
"mp": 30,
"type" : 2,
"birthday": "2000-07-20"
}
},
{
"model": "study.monster",
"pk": 3,
"fields": {
"name": "DarkDragon",
"hp": 100,
"mp": 100,
"type" : 3,
"birthday": "2000-08-05"
}
},
{
"model": "study.monster",
"pk": 4,
"fields": {
"name": "Slime",
"hp": 10,
"mp": 10,
"type" : 2,
"birthday": "2001-09-20"
}
},
{
"model": "study.monster",
"pk": 5,
"fields": {
"name": "KingSlime",
"hp": 80,
"mp": 80,
"type" : 2,
"birthday": "2001-08-12"
}
},
{
"model": "study.monster",
"pk": 6,
"fields": {
"name": "DarkKnight",
"hp": 30,
"mp": 60,
"type" : 3,
"birthday": "2001-04-10"
}
},
{
"model": "study.monster",
"pk": 7,
"fields": {
"name": "FireGoblin",
"hp": 50,
"mp": 30,
"type" : 1,
"birthday": "2002-08-25"
}
}
]
マイグレーション
初期マイグレーションファイルを作成します
$ python manage.py makemigrations
Fixtureデータを登録するための空のマイグレーションファイルを作成します
$ python manage.py makemigrations アプリ名 --empty
マイグレーションファイルの修正
from django.db import migrations
from django.core.management import call_command
def load_fixture(apps, schema_editor):
call_command('loaddata', 'study/fixtures/monster.json', app_label='study')
class Migration(migrations.Migration):
dependencies = [
('study', '0001_initial'),
]
operations = [
migrations.RunPython(load_fixture),
]
マイグレーション実行
$ python manage.py migrate
all
全件を取得する
Monster.objects.all()
SELECT
`monster`.`id`,
`monster`.`name`,
`monster`.`hp`,
`monster`.`mp`,
`monster`.`type`,
`monster`.`birthday`
FROM
`monster`
filter
引数にカラム名を条件を指定して検索する
id=1を取得する
Monster.objects.filter(id=1)
SELECT
`monster`.`id`,
`monster`.`name`,
`monster`.`hp`,
`monster`.`mp`,
`monster`.`type`,
`monster`.`birthday`
FROM
`monster`
WHERE
`monster`.`id` = 1
name=FireDragonを取得する
Monster.objects.filter(name="FireDragon")
SELECT
`monster`.`id`,
`monster`.`name`,
`monster`.`hp`,
`monster`.`mp`,
`monster`.`type`,
`monster`.`birthday`
FROM
`monster`
WHERE
`monster`.`name` = 'FireDragon'
HPが40以下、かつMPが20以上
# 複数を並べた場合、AND演算になる。この場合、HPが40以下、かつMPが20以上になる
Monster.objects.filter(hp__lte=40, mp__gte=20)
SELECT
`monster`.`id`,
`monster`.`name`,
`monster`.`hp`,
`monster`.`mp`,
`monster`.`type`,
`monster`.`birthday`
FROM
`monster`
WHERE
(`monster`.`hp` <= 40 AND `monster`.`mp` >= 20)
exclude
与えられた条件にマッチしない結果セットを返します
id=1以外を取得する
# idが1以外を取得する
Monster.objects.exclude(id=1)
SELECT
`monster`.`id`,
`monster`.`name`,
`monster`.`hp`,
`monster`.`mp`,
`monster`.`type`,
`monster`.`birthday`
FROM
`monster`
WHERE
NOT (`monster`.`id` = 1)
name=FireDragon以外を取得する
# nameがFireDragon以外を取得する
Monster.objects.exclude(name="FireDragon")
SELECT
`monster`.`id`,
`monster`.`name`,
`monster`.`hp`,
`monster`.`mp`,
`monster`.`type`,
`monster`.`birthday`
FROM
`monster`
WHERE
NOT (`monster`.`name` = 'FireDragon')
hpが40以下、かつmpが20以上ではないを取得する
# HPが40以下、かつMPが20以上以外を取得する
Monster.objects.exclude(hp__lte=40, mp__gte=20)
SELECT
`monster`.`id`,
`monster`.`name`,
`monster`.`hp`,
`monster`.`mp`,
`monster`.`type`,
`monster`.`birthday`
FROM
`monster`
WHERE
NOT (`monster`.`hp` <= 40 AND `monster`.`mp` >= 20)
get
1件を取得します。特定のモデルインスタンスを取得します。条件に一致したレコードが存在しない場合、エラーになります。条件に一致したレコードが複数県の場合、エラーになります
id=1を取得する
Monster.objects.get(id=1)
SELECT
`monster`.`id`,
`monster`.`name`,
`monster`.`hp`,
`monster`.`mp`,
`monster`.`type`,
`monster`.`birthday`
FROM
`monster`
WHERE
`monster`.`id` = 1
name=FireDragonを取得する
Monster.objects.get(name="FireDragon")
SELECT
`monster`.`id`,
`monster`.`name`,
`monster`.`hp`,
`monster`.`mp`,
`monster`.`type`,
`monster`.`birthday`
FROM
`monster`
WHERE
`monster`.`name` = 'FireDragon'
ordder_by
並び替えます。引数でカラム名を指定します。昇順に並び替えます
idで昇順に並び替える
Monster.objects.order_by("id")
SELECT
`monster`.`id`,
`monster`.`name`,
`monster`.`hp`,
`monster`.`mp`,
`monster`.`type`,
`monster`.`birthday`
FROM
`monster`
ORDER BY
`monster`.`id` ASC
hpで昇順に並び替える
Monster.objects.order_by("hp")
SELECT
`monster`.`id`,
`monster`.`name`,
`monster`.`hp`,
`monster`.`mp`,
`monster`.`type`,
`monster`.`birthday`
FROM
`monster`
ORDER BY
`monster`.`hp` ASC
mp, hpの昇順で並び替える
Monster.objects.order_by("mp","hp")
SELECT
`monster`.`id`,
`monster`.`name`,
`monster`.`hp`,
`monster`.`mp`,
`monster`.`type`,
`monster`.`birthday`
FROM
`monster`
ORDER BY
`monster`.`mp` ASC,
`monster`.`hp` ASC
reverse
降順に並び替えます。引数でカラム名を指定します
idで降順
Monster.objects.order_by("id").reverse()
SELECT
`monster`.`id`,
`monster`.`name`,
`monster`.`hp`,
`monster`.`mp`,
`monster`.`type`,
`monster`.`birthday`
FROM
`monster`
ORDER BY
`monster`.`id` DESC
mp, hpで降順
Monster.objects.order_by("mp","hp").reverse()
SELECT
`monster`.`id`,
`monster`.`name`,
`monster`.`hp`,
`monster`.`mp`,
`monster`.`type`,
`monster`.`birthday`
FROM
`monster`
ORDER BY
`monster`.`mp` DESC,
`monster`.`hp` DESC
first
先頭の1件を取得します。戻り値はQuerySetではなく、モデルのインスタンスです。filter, order_by, reverseなどと併用することが可能です。該当するレコードがない場合、Noneを返します
hpが40以下をhpで昇順に並び替えた先頭の1件
Monster.objects.filter(hp__lte=40).order_by("hp").first()
SELECT
`monster`.`id`,
`monster`.`name`,
`monster`.`hp`,
`monster`.`mp`,
`monster`.`type`,
`monster`.`birthday`
FROM
`monster`
WHERE
`monster`.`hp` <= 40
ORDER BY
`monster`.`hp` ASC
LIMIT
1
last
最後の1件を取得します。戻り値はQuerySetではなく、モデルのインスタンスです。filter, order_by, reverseなどと併用することが可能です。該当するレコードがない場合、Noneを返します
hpが40以下をhpで昇順に並び替えた最後の1件
Monster.objects.filter(hp__lte=40).order_by("hp").first()
SELECT
`monster`.`id`,
`monster`.`name`,
`monster`.`hp`,
`monster`.`mp`,
`monster`.`type`,
`monster`.`birthday`
FROM
`monster`
WHERE
`monster`.`hp` <= 40
ORDER BY
`monster`.`hp` DESC
LIMIT
1
OR検索
WHERE句でのOR検索を行います。filterの場合、AND検索になります
from django.db.models import Q
hpが40以下、またはmpが20以上
Monster.objects.filter(Q(hp__lte=40) | Q(mp__gte=20))
SELECT
`monster`.`id`,
`monster`.`name`,
`monster`.`hp`,
`monster`.`mp`,
`monster`.`type`,
`monster`.`birthday`
FROM
`monster`
WHERE
`monster`.`hp` <= 40
OR
`monster`.`mp` >= 20
範囲指定
範囲を指定した取り出します。Pythonのスライスを利用して特定の範囲を切り出します
hpで昇順に並び替えて、インデックスで2から4までを取得
Monster.objects.all().order_by("hp")[2:4]
SELECT
`monster`.`id`,
`monster`.`name`,
`monster`.`hp`,
`monster`.`mp`,
`monster`.`type`,
`monster`.`birthday`
FROM
`monster`
ORDER BY
`monster`.`hp` ASC
LIMIT
2
OFFSET
2
values
モデルのオブジェクトの結果セットではなく、ディクショナリ形式の結果セットで取得します。引数でカラム名を指定すると、特定のカラムだけ取得します
hpが80以上でディクショナリ形式で取得する
Monster.objects.filter(hp__gte=80).values()
SELECT
`monster`.`id`,
`monster`.`name`,
`monster`.`hp`,
`monster`.`mp`,
`monster`.`type`,
`monster`.`birthday`
FROM
`monster`
WHERE
`monster`.`hp` >= 80
QuerySet [
{
'id': 3,
'name': 'DarkDragon',
'hp': 100,
'mp': 100,
'type': 3,
'birthday': datetime.date(2000, 8, 5)
},
{
'id': 5,
'name': 'KingSlime',
'hp': 80,
'mp': 80,
'type': 2,
'birthday': datetime.date(2001, 8, 12)
}
]>
hpが80以上でid, name, hpをディクショナリ形式で取得する
Monster.objects.filter(hp__gte=80).values("id","name","hp")
SELECT
`monster`.`id`,
`monster`.`name`,
`monster`.`hp`
FROM
`monster`
WHERE
`monster`.`hp` >= 80
<QuerySet [
{
'id': 3,
'name': 'DarkDragon',
'hp': 100
},
{
'id': 5,
'name': 'KingSlime',
'hp': 80
}
]>
values_list
モデルのオブジェクトの結果セットではなく、タプル形式の結果セットで取得します。引数でカラム名を指定すると、特定のカラムだけ取得します
hpが80以上でタプル形式で取得する
Monster.objects.filter(hp__gte=80).values_list()
SELECT
`monster`.`id`,
`monster`.`name`,
`monster`.`hp`,
`monster`.`mp`,
`monster`.`type`,
`monster`.`birthday`
FROM
`monster`
WHERE
`monster`.`hp` >= 80
<QuerySet [
(3, 'DarkDragon', 100, 100, 3, datetime.date(2000, 8, 5)),
(5, 'KingSlime', 80, 80, 2, datetime.date(2001, 8, 12))
]>
hpが80以上でid, name, hpをタプル形式で取得する
Monster.objects.filter(hp__gte=80).values_list("id","name","hp")
SELECT
`monster`.`id`,
`monster`.`name`,
`monster`.`hp`
FROM
`monster`
WHERE
`monster`.`hp` >= 80
<QuerySet [
(3, 'DarkDragon', 100),
(5, 'KingSlime', 80)
]>
exists
結果セットが存在するかどうかを真偽値で返します
id=1の存在確認
Monster.objects.filter(id=1).exists()
SELECT
1 AS `a`
FROM
`monster`
WHERE
`monster`.`id` = 1
True
id=100の存在確認
Monster.objects.filter(id=100).exists()
SELECT
1 AS `a`
FROM
`monster`
WHERE
`monster`.`id` = 100
False
name="xxx"の存在確認
Monster.objects.filter(name="xxx").exists()
SELECT
1 AS `a`
FROM
`monster`
WHERE
`monster`.`name` = 'xxx'
s
False
count
件数を取得します。数値が返ります
全件数の取得
Monster.objects.all().count()
SELECT
COUNT(*) AS `__count`
FROM
`monster`
7
hpが40以上の件数の取得
Monster.objects.filter(hp__gte=40).exists()
SELECT
1 AS `a`
FROM
`monster`
WHERE
`monster`.`hp` >= 40
True
aggregate
集計を行います。集計値(合計、平均など)をディクショナリ形式で返します
集計用の関数のインポート
from django.db.models import Count, Sum, Avg, Min, Max
全件の件数
この場合、countと同じですが、とりあえず、aggregateでも実現可能です
: Monster.objects.aggregate(Count("id"))
SELECT
COUNT(`monster`.`id`) AS `id__count`
FROM
`monster`
{'id__count': 7}
HPが40以上の件数
Monster.objects.filter(hp__gte=40).aggregate(Count("hp"))
SELECT
COUNT(`monster`.`hp`) AS `hp__count`
FROM
`monster`
WHERE
`monster`.`hp` >= 40
{'hp__count': 4}
HPが40以上の合計値
Monster.objects.filter(hp__gte=40).aggregate(Sum("hp"))
SELECT
SUM(`monster`.`hp`) AS `hp__sum`
FROM
`monster`
WHERE
`monster`.`hp` >= 40
{'hp__sum': 270}
HPが40以上の平均値
Monster.objects.filter(hp__gte=40).aggregate(Avg("hp"))
SELECT
AVG(`monster`.`hp`) AS `hp__avg`
FROM
`monster`
WHERE
`monster`.`hp` >= 40
{'hp__avg': 67.5}
HPの最大値
Monster.objects.filter(hp__gte=40).aggregate(Max("hp"))
SELECT
MAX(`monster`.`hp`) AS `hp__max`
FROM
`monster`
WHERE
`monster`.`hp` >= 40
{'hp__max': 100}
Discussion