ORM

Django ORMのvalues入門|指定フィールドのみ取得する方法

Django ORMで必要なフィールドだけを指定してデータを取得する方法を解説します。values()values_list()only()を使うと、不要なフィールドの読み込みを省略してパフォーマンスを向上できます。

values()の基本的な使い方

values()を使うと、指定したフィールドのみを辞書形式で取得できます。

views.py
from .models import Sale

def index(request):
    # amountとsales_dateフィールドのみ取得
    sales = Sale.objects.values('amount', 'sales_date')
    print(sales)
実行結果
<QuerySet [
    {'amount': 10000, 'sales_date': datetime.date(2025, 1, 15)},
    {'amount': 25000, 'sales_date': datetime.date(2025, 1, 20)},
    {'amount': 8000, 'sales_date': datetime.date(2025, 2, 3)}
]>

values()はモデルインスタンスではなく辞書のクエリセットを返します。SQLのSELECT amount, sales_date FROM saleに相当します。

values_list()でタプル形式で取得

values_list()を使うと、タプル形式でデータを取得できます。

views.py
# タプルのリストとして取得
sales = Sale.objects.values_list('amount', 'sales_date')
# [(10000, datetime.date(2025, 1, 15)), (25000, datetime.date(2025, 1, 20)), ...]

# flat=Trueで単一フィールドのリストを取得
amounts = Sale.objects.values_list('amount', flat=True)
# [10000, 25000, 8000, ...]

# named=Trueで名前付きタプルとして取得
sales = Sale.objects.values_list('amount', 'sales_date', named=True)
# [Row(amount=10000, sales_date=datetime.date(2025, 1, 15)), ...]

flat=Trueは1つのフィールドだけを取得する場合に便利です。リストのように扱えます。

only()でモデルインスタンスとして取得

only()を使うと、指定フィールドだけを読み込んだモデルインスタンスを取得できます。

views.py
# amountとsales_dateのみ読み込んだSaleインスタンスを取得
sales = Sale.objects.only('amount', 'sales_date')

for sale in sales:
    print(sale.amount)       # 追加クエリなし
    print(sale.sales_date)   # 追加クエリなし
    print(sale.customer_id)  # ※ 遅延読み込みで追加クエリが発生

only()はモデルインスタンスを返すため、メソッドやプロパティにアクセスできます。ただし、指定外のフィールドにアクセスすると遅延読み込みで追加クエリが発生します。

defer()で除外フィールドを指定

defer()only()の逆で、読み込みを遅延させるフィールドを指定します。

views.py
# descriptionフィールドだけ遅延読み込みにする
sales = Sale.objects.defer('description', 'notes')

# 大きなテキストフィールドを除外したい場合に便利

filterやorderと組み合わせる

これらのメソッドは他のクエリメソッドと自由に組み合わせられます。

views.py
# filterと組み合わせる
high_sales = Sale.objects.filter(
    amount__gt=10000
).values('amount', 'sales_date')

# orderと組み合わせる
ordered = Sale.objects.values(
    'amount', 'customer_id'
).order_by('-amount')

# limitと組み合わせる
top_5 = Sale.objects.values(
    'product_name', 'amount'
).order_by('-amount')[:5]

# 関連モデルのフィールドも取得可能
sales_with_customer = Sale.objects.values(
    'amount', 'customer__name'
)

実践的な使用例

APIレスポンスやCSV出力など、特定のフィールドだけが必要な場面での活用例です。

views.py
from django.http import JsonResponse
from .models import Sale

def sale_api(request):
    # JSONレスポンス用に必要なフィールドのみ取得
    sales = list(Sale.objects.filter(
        sales_date__year=2025
    ).values('id', 'product_name', 'amount', 'sales_date'))

    return JsonResponse({'sales': sales})

def export_amounts(request):
    # CSVエクスポート用にamountのリストを取得
    amounts = Sale.objects.values_list('amount', flat=True)
    total = sum(amounts)
    return JsonResponse({'amounts': list(amounts), 'total': total})
ポイント

values()only()の使い分け: テンプレートでモデルのメソッドやプロパティを使う場合はonly()、辞書データだけで十分な場合(API、集計など)はvalues()を使いましょう。values()の方がメモリ効率が良いです。

注意

only()で指定していないフィールドにアクセスすると、1件ごとに追加のSQLクエリが発生します(N+1問題と同じ)。必要なフィールドは全てonly()に含めてください。

まとめ

  • values('field1', 'field2')で指定フィールドを辞書形式で取得できる
  • values_list(flat=True)で単一フィールドのリストを取得できる
  • only()はモデルインスタンスとして返すため、メソッドも使える
  • defer()は除外するフィールドを指定する(onlyの逆)
  • 不要なフィールドを省くことでメモリ使用量とクエリ速度が改善される