はじめに
この記事では、Pydanticを使用して、2つのオプションフィールドのうちどちらかがNoneでないことを検証する方法を紹介します。
Field1 または Field2 が None でないことを検証
まず、2つのオプションフィールドのうちどちらかがNoneでないことを検証するために、これらのフィールドを持つPydanticモデルを準備します。この例では、2つのオプション文字列フィールドfield1とfield2を持つExampleモデルを作成します。
from typing import Optional
from pydantic import BaseModel
class Example(BaseModel):
field1: Optional[str] = None
field2: Optional[str] = None
ここでは、typingモジュールからOptional型をインポートして、オプションフィールドを定義することができます。また、pydanticモジュールからBaseModelクラスをインポートして、モデルを作成するために使用します。
Exampleクラスでは、2つのオプション文字列フィールドfield1とfield2を定義しています。デフォルト値をNoneに設定しているため、これらのフィールドはオプションであり、値が提供されていない場合はNoneであることができます。
field1またはfield2のどちらかがNoneでないことを検証するには、Pydanticのvalidatorデコレータを使用します。このデコレータを使用すると、フィールドまたはフィールドのセットのカスタム検証ロジックを定義できます。
Exampleクラスでは、validatorメソッドとしてcheck_either_not_noneを定義し、2つの引数vとvaluesを受け取ります。v引数は検証されているフィールド (field1またはfield2) の値を表し、values引数は検証されている全ての値の辞書を表します。
from typing import Optional, Any
from pydantic import BaseModel, validator
class Example(BaseModel):
field1: Optional[str] = None
field2: Optional[str] = None
@validator('field1', 'field2', pre=True)
def check_either_not_none(cls, v: Optional[str], values: dict, **kwargs: Any) -> Optional[str]:
if not kwargs.get("validate_assignment"):
return v
if v is None and values.get('field2') is None:
raise ValueError('either field1 or field2 must not be None')
return v
ここでは、validatorデコレータでcheck_either_not_noneメソッドを修飾し、検証するフィールドの名前 (field1およびfield2) を文字列で渡します。
メソッド内では、まず検証されているフィールド (v) の値がNoneかどうかをチェックします。もしNoneであれば、values.get('field2')を使用して他のフィールド (field2) の値がNoneかどうかをチェックします。両方のフィールドがNoneの場合は、ValueErrorをスローし、少なくとも1つのフィールドがNoneであってはならないことを示すメッセージを表示します。
フィールドのいずれかがNoneでない場合は、検証されているフィールド (v) の値を返します。
この検証ロジックが定義された状態で、Exampleモデルのインスタンスを作成し、検証をテストすることができます。
example = Example(field1='hello', field2=None)
この例では、field1には'hello'が設定され、field2にはNoneが設定されています。field1がNoneでないため、検証に合格し、エラーなしでExampleモデルのインスタンスを作成することができます。
両方のフィールドがNoneに設定されたインスタンスを作成しようとした場合、ValueErrorが発生します。
example = Example(field1=None, field2=None)
この場合、field1またはfield2のどちらかがNoneである必要があるため、ValueErrorが発生します。