ORMクエリの最適化戦略
データベースへの不要なアクセスを削減し、パフォーマンスを向上させるための手法として、Django ORMは複数の最適化メソッドを提供しています。ここでは、主要な4つのメソッドについて解説します。
only()とdefer()の使い分け
only()メソッドは、指定したフィールドのみを取得対象とします。取得結果のオブジェクトから、指定したフィールドにアクセスする場合は追加のクエリが発生しませんが、指定外のフィールドにアクセスすると新たにクエリが実行されます。
# タイトルのみ取得
books = Book.objects.only('title')
for book in books:
print(book.title) # クエリ発行なし
print(book.price) # 各ループでクエリ発行defer()はonly()と逆の動作をします。指定したフィールドを遅延読み込みの対象とし、それ以外のフィールドは即座に取得されます。
# タイトル以外を取得
books = Book.objects.defer('title')
for book in books:
print(book.price) # クエリ発行なし
print(book.title) # 各ループでクエリ発行select_related()とprefetch_related()の違い
select_related()は、外部キー関係(一対一、多対一)に対してJOINを行い、単一のクエリで関連データを取得します。
# INNER JOINで一括取得
books = Book.objects.select_related('publisher')
for book in books:
print(book.publisher.name) # 追加クエリなしprefetch_related()は、多対多関係や逆参照に対して使用し、複数のクエリを発行した後にPythonレベルで結合を行います。
# 複数クエリで取得後に結合
books = Book.objects.prefetch_related('authors')
for book in books:
for author in book.authors.all():
print(author.name) # 追加クエリなし大きなテーブルを扱う場合、select_related()はJOINの負荷が高くなる可能性があるため、状況に応じて使い分けることが重要です。
MTVとMVCアーキテクチャ
DjangoはMTV(Model-Template-View)アーキテクチャを採用していますが、これは本質的にMVC(Model-View-Controller)パターンと同じ概念です。
- Model: データベースとのやり取りを担当
- Template: ユーザーインターフェースの表示(MVCのViewに相当)
- View: ビジネスロジックの処理(MVCのControllerに相当)
choicesパラメータの活用
性別やステータスなど、選択肢が限定的なフィールドに対してchoicesパラメータを使用すると、データベースには数値を保存しつつ、表示時には対応する文字列を取得できます。
class Member(models.Model):
STATUS_CHOICES = [
(1, 'アクティブ'),
(2, '非アクティブ'),
(3, '退会'),
]
status = models.IntegerField(choices=STATUS_CHOICES)
# 使用例
member = Member.objects.get(pk=1)
print(member.get_status_display()) # "アクティブ"と表示get_<フィールド名>_display()メソッドで対応する文字列を取得できます。定義されていない値が保存されている場合、その値がそのまま返されます。
AJAXの基礎と実装
AJAX(Asynchronous JavaScript And XML)を使用すると、ページ全体をリロードすることなく、サーバーとデータをやり取りし、ページの一部を更新できます。
基本的なAJAXリクエスト
$('#calculate').click(function() {
$.ajax({
url: '/api/calculate/',
type: 'POST',
data: {
'num1': $('#input1').val(),
'num2': $('#input2').val()
},
success: function(response) {
$('#result').val(response);
}
});
});JSONデータの送信
JSON形式でデータを送信する場合、contentTypeを指定し、データをシリアライズする必要があります。
$.ajax({
url: '/api/data/',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({
'username': 'user1',
'password': 'pass123'
}),
success: function(response) {
console.log(response);
}
});Django側ではrequest.bodyからJSONデータを取得します。
import json
from django.http import JsonResponse
def api_view(request):
if request.is_ajax():
data = json.loads(request.body.decode('utf-8'))
return JsonResponse(data)
return render(request, 'index.html')ファイルのアップロード
FormDataオブジェクトを使用して、ファイルとテキストデータを同時に送信できます。
$('#upload').click(function() {
let formData = new FormData();
formData.append('username', 'user1');
formData.append('avatar', $('#fileInput')[0].files[0]);
$.ajax({
url: '/api/upload/',
type: 'POST',
data: formData,
contentType: false,
processData: false,
success: function(response) {
alert('アップロード完了');
}
});
});Django側ではrequest.FILESでファイルデータを受け取ります。
シリアライズ機能
Djangoのserializersモジュールを使用すると、クエリセットをJSON形式に変換できます。
from django.core import serializers
def export_data(request):
members = Member.objects.all()
json_data = serializers.serialize('json', members)
return HttpResponse(json_data, content_type='application/json')出力形式は以下のようになります:
[
{"model": "app.member", "pk": 1, "fields": {"name": "田中", "status": 1}},
{"model": "app.member", "pk": 2, "fields": {"name": "佐藤", "status": 2}}
]