ORM

Django ORMでNULL値にデフォルト値を設定|Coalesceの使い方

DjangoのORMで、フィールドの値がNULLの場合にデフォルト値を代入するには、Coalesce関数を使用します。SQLのCOALESCE関数に対応し、NULL値の処理を簡潔に記述できます。

基本的な使い方

views.py
from django.db.models.functions import Coalesce
from django.utils import timezone

model=Sales.objects.annotate(test=Coalesce('date', timezone.now()))
print(model.values('test'))

説明

Step 1Coalesce関数の基本

Djangoでは、Coalesce関数を使用してフィールドの値がNULLの場合のデフォルト値を設定することができます。基本的な構文は以下の通りです:

from django.db.models import Coalesce, Value

Coalesce(データがあるときの値, データがないときの値)

Coalesce関数は最初の引数がNULLでなければその値を、NULLであれば次の引数を返します。これを使って、フィールドにデフォルト値を設定できます。

Step 2基本的な使用例

例えば、dateフィールドがない場合に現在の日時をデフォルト値として設定する場合:

from django.db.models import Coalesce, Value
from django.utils import timezone

# dateフィールドがあればそれを、なければ現在時刻を使用
records = MyModel.objects.annotate(
    test=Coalesce('date', Value(timezone.now()))
)

上の例では、testフィールドに、dateフィールドがあればdateを、なければ今の日時を代入しています。

Step 3様々なデータ型での使用例

Coalesce関数は様々なタイプのデータで使用できます:

# 数値フィールドのデフォルト値
products = Product.objects.annotate(
    actual_price=Coalesce('sale_price', 'regular_price')
)

# 文字列フィールドのデフォルト値
persons = Person.objects.annotate(
    display_name=Coalesce('nickname', 'full_name', Value('名称未設定'))
)

# ブール値フィールドのデフォルト値
from django.db.models import BooleanField
tasks = Task.objects.annotate(
    is_important=Coalesce('priority_flag', Value(False), output_field=BooleanField())
)

Coalesceは2つ以上の引数を取ることができ、最初のNULLでない値を返します。

Step 4関連モデルのフィールドでの使用

関連モデルのフィールドにもCoalesceを適用できます:

# 所属部署名がない場合に「所属なし」と表示
persons = Person.objects.annotate(
    department_name=Coalesce('department__name', Value('所属なし'))
)

# 最終売上日がない場合に「未売上」と表示
from django.db.models import Max, CharField
persons = Person.objects.annotate(
    last_sale_date=Max('sales__date')
).annotate(
    last_sale_display=Coalesce(
        'last_sale_date', 
        Value('未売上'),
        output_field=CharField()
    )
)

異なるデータ型を扱う場合は、output_fieldパラメータで結果の型を指定する必要があります。

Step 5計算フィールドでの使用

計算結果がNULLになる可能性がある場合にデフォルト値を設定:

from django.db.models import F, DecimalField

# 割引率がNULLの場合は割引なし(1.0)として計算
products = Product.objects.annotate(
    discount_factor=Coalesce('discount_rate', Value(1.0)),
    sale_price=F('regular_price') * F('discount_factor')
)

# 除算でゼロ除算を防ぐ
from django.db.models import ExpressionWrapper
orders = Order.objects.annotate(
    safe_denominator=Coalesce('quantity', Value(1)),  # 0や NULL を 1 に置き換え
    unit_cost=ExpressionWrapper(
        F('total_cost') / F('safe_denominator'),
        output_field=DecimalField(max_digits=10, decimal_places=2)
    )
)

Step 6実践的な使用例

views.pyでのCoalesce関数の使用例:

from django.shortcuts import render
from django.db.models import Coalesce, Value, Sum, Count, CharField, F
from .models import Person, Sales

def sales_dashboard(request):
    # 売上データがない場合のデフォルト値を設定
    persons = Person.objects.annotate(
        # 売上件数(デフォルト0)
        sales_count=Coalesce(Count('sales'), Value(0)),
        
        # 売上合計(デフォルト0)
        total_sales=Coalesce(Sum('sales__amount'), Value(0)),
        
        # 最終売上日(デフォルト「未売上」)
        last_sale_date=Max('sales__date'),
        last_sale_display=Coalesce(
            'last_sale_date', 
            Value('未売上'),
            output_field=CharField()
        ),
        
        # 平均売上単価(デフォルト0、ゼロ除算回避)
        safe_count=Coalesce(Count('sales'), Value(1)),  # 0を避けるため最小値1
        avg_sale=Coalesce(
            Sum('sales__amount') / F('safe_count'),
            Value(0)
        )
    ).order_by('-total_sales')
    
    return render(request, 'persons/dashboard.html', {
        'persons': persons
    })

テンプレートでの使用例(dashboard.html):

<h1>営業担当者ダッシュボード</h1>

<table>
    <tr>
        <th>担当者名</th>
        <th>売上件数</th>
        <th>売上合計</th>
        <th>最終売上日</th>
        <th>平均売上単価</th>
    </tr>
    {% for person in persons %}
        <tr>
            <td>{{ person.name }}</td>
            <td>{{ person.sales_count }}件</td>
            <td>{{ person.total_sales|floatformat:0 }}円</td>
            <td>{{ person.last_sale_display }}</td>
            <td>{{ person.avg_sale|floatformat:0 }}円</td>
        </tr>
    {% endfor %}
</table>
重要ポイント:
  • Coalesce関数はSQLのCOALESCE関数に相当し、データベースレベルで処理されます。
  • 複数の引数を渡すことができ、最初のNULLでない値が返されます。
  • 異なるデータ型の値を扱う場合は、output_fieldパラメータで結果の型を指定する必要があります。
  • ゼロ除算や未設定値によるエラーを防ぐためにCoalesceを使用すると、コードの堅牢性が向上します。
  • 集計関数(Sum, Count, Max等)と組み合わせることで、データがない場合の適切なデフォルト値を設定できます。

まとめ

  • Coalesce()で最初のNULLでない値を返すことができる
  • 集計関数の結果がNULLの場合のデフォルト値設定に便利
  • 複数の引数を指定でき、左から順にNULLでない最初の値が使われる
  • annotate()と組み合わせて、NULLを0やデフォルト文字列に置換できる
  • SQLのCOALESCE関数と同等の動作をする