クエリの基本
基本のクエリ
世の中にあるほぼ全てのWebサービスがデータベースと連携してデータを扱っています。
そのデータベースに接続してデータの取得などの操作をすることをクエリと言います。
またPythonなどSQLではない言語を使用してデータを操作することをORMと言います。
ORMは、オブジェクト関係マッピングといい、英語ではObject-Relational Mapping と言います。
Djangoにも特有のORMが存在します。そのためDjangoのプロジェクト内ではSQLを使わなくても、Pythonの記法でデータベースにアクセスしデータを操作することが簡単にできます。
Djangoを使いこなす上でDjangoのORMは切っても切り離せない関係です。
まずは基本から見ていきましょう。
データの全取得
該当するテーブル(class)のデータを全取得するには、object.all()を使います。
以下のmodels.pyがあるとしましょう。
models.py
class Article(models.Model):
title = models.CharField(max_length=100)
body = models.TextField()
is_published = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True)
class Comment(models.Model):
article = models.ForeignKey(Article, on_delete=models.CASCADE)
body = models.TextField()
created = models.DateTimeField(auto_now_add=True)
存在する全てのArticleデータを取得したい場合、下記のようにすることでデータを取得することができます。
例
from .models import Article
articles = Article.objects.all()
データのソート
データを複数取得する際は、順番をソートすることも可能です。
この場合最後にorder_by()
を加えます。
from .models import Article
articles = Article.objects.all().order_by('created')
order_by('created')
を加えることで、データを古い順から取得することができます。
また値の先頭に-
を加えることでソートの順を逆順にすることができます。
order_by('-created')
とすることで、今度はデータを新しい順から取得することができます。
データのフィルタリング
データを全て取得したいケースは稀です。
多くの場合、フィルタリングをかけて、特定の要件に該当するデータのみを取得したいはずです。この場合objects.filter()
を使います。
from .models import Article
published_articles = Article.objects.filter(is_published=True)
これで、is_publishedがTrueのArticleのみ取得することができます。
フィルタリングは基本完全一致ですが、~以上や~未満、~を含むか、など様々な要件でフィルタリングをかけることができます。
__in
__in
を使うと、指定するリストの中に該当するデータのみを引っ張ってくることができます。
例
from .models import Article
sample_titles = ['test', 'sample_title']
published_articles = Article.objects.filter(title__in=sample_titles)
__gt, __lt
__gt
はプログラミングの>
に該当します。つまり指定する値より大きい場合にフィルタリングにヒットします。
__lt
はプログラミングの<
に該当します。つまり指定する値より小さい場合にフィルタリングにヒットします。
例
from .models import Article
target_date = '2020-10-01'
published_articles = Article.objects.filter(created__gt=target_date)
これで2020年10月1日より新しいArticleのみ取得することができます。
__lt
にすればtarget_dateより古いArticleのみを取得します。
またgtとltにそれぞれeを加えると同じ値も含むようになります。プログラミングでいう所の<=
と>=
になります。
例
from .models import Article
target_date = '2020-10-01'
published_articles = Article.objects.filter(created__lte=target_date)
全て英語の略称になってるので英語で覚えると良いでしょう。
- gt
greater than - gte
greater than equal - lt
lower than - lte
lower than equal
フィルタリングのデータ作成
フィルタリング項目はあらかじめ辞書型で作成することができます。
通例、conditionという変数名を使用して、辞書型のデータを作成します。
あとはfilter(**condition)
という形でデータを入れ込みます。
例
from .models import Article
condition = {
'created__gte': '2020-10-01',
'is_published': True,
}
published_articles = Article.objects.filter(**condition)
これであらかじめ作成したフィルタリング項目を使用して、データを取得することができます。
クエリの応用
objects.all()
やobjects.filter()
で作成したクエリを応用することでデータの有無の確認や、データ数のカウントなどができます。
exists
exists()
を使えば、そのデータが存在するときにTrue
、存在しない場合はFalse
を返すことができます。
例
from .models import Article
condition = {
'created__gte': '2020-10-01',
'is_published': True,
}
article_exists = Article.objects.filter(**condition).exists()
例えばデータの中身は必要ないけど、データが存在するかどうかを確認したいときはexists()
を使うと良いでしょう。
count
count()
を使えば、そのデータの個数を確認することができます。
例
from .models import Article
condition = {
'created__gte': '2020-10-01',
'is_published': True,
}
article_count = Article.objects.filter(**condition).count()
これもデータの中身は必要ないけど、該当するデータの個数を確認したいときに使用すると良いでしょう。
また、データの数の確認を行うだけでもデータベースに接続し、データを操作するアクションは行われます。
処理の最適化のために、データは取得しておきたいし個数も確認したい場合、Python関数のlen()
を使用しましょう。
例
from .models import Article
condition = {
'created__gte': '2020-10-01',
'is_published': True,
}
articles = Article.objects.filter(**condition)
article_count = len(articles)
これでクエリは1度で、データの内容も個数も取得することができます。
#### データの単体取得
`objects.all()`や`objects.filter()`は、クエリセット と言われるデータ型でデータを取得します。これは少しリストに似た形になっており例えデータが一つも存在しない場合でもプログラムを実行することができます。
これとは反対に単体のデータ(オブジェクト)を取得するのが`objects.get()`です。
`objects.get()`も`objects.filter()`と同じようにフィルタリングをかけることが可能です。
注意しなければいけないのは、仮にデータが1つもない場合、もしくは複数存在する場合その時点でエラーが返されることです。
Djangoのサービス運用をする上で、この類のエラーは頻発してしまうので注意して扱いましょう。
公式ドキュメントでは、必ずデータが1つしかないとわかっている時に使用しましょう。と書いてあります。
例
```.py
from .models import Article
article = Article.objects.get(title='sample_title')
objects.all()
やobjects.filter()
はリストに似た型のクエリセット を取得するので実際はfor文やインデックス指定をして、データの中身を取り出します。
例
articles = Article.objects.all()
for article in articles:
print(article.title)
print(article[0].title)
objects.get()
では取得したそのままフィールド値を取り出すことができます。
例
article = Article.objects.get(title='sample_title')
print(article.title)
まずは、これら3つをうまく使いこなしていければ良いでしょう。
Just Python フリープラン
ジャスパイなら教材は全て無料!