やりたいこと
PythonのCerberusライブラリは、本来ヌルチェックや桁数チェックなどいろんなチェックができるけど、プロジェクトの要望のより、どうしてもチェックできない条件が出てしまって、、、
今回の場合、データの「A項目とB項目いずれか存在していること」を確保したいので、CerberusのValidatorをカスタマイズしてみました~
前提
・Pythonインストール済み
・pipenvインストール済み
(今回は便宜上pipenvでやるのですが、ローカルでcerberusなど諸々ライブラリを入れてテストをやっても大丈夫です)
ソースの中身
さっそく調べた結果をソース化しました~
今回は「name」項目と「nickName」項目のいずれに存在している(ヌルかブランクではない)ことをチェックします
まずは、カスタマイズしたValidatorクラスを紹介します~
from cerberus import Validator
# Validatorクラスを継承する
class CustomizedValidator(Validator):
def __init__(self, *args, **kwargs):
super(CustomizedValidator, self).__init__(*args, **kwargs)
# メソッド名は「_validate」始まりで、後ろに自由に命名できる
def _validate_true_either_or(self, schema_value, field, value):
"""
指定した二項目の中に、少なくとも1つの値が存在しているであること
:param schema_value: スキーマの値
:param field: 項目名
:param value: 項目値
The rule's arguments are validated against this schema: {'type': 'string'}
"""
# まずは、データの行(全項目の値)を取得する
item = self.root_document
# ここからは、自作のチェックコード
# 異常時のエラー文も自作できる
if len(item[field]) == 0 and len(item[schema_value]) == 0:
self._error(field, f'either {schema_value} or {field} must have value')
データの行(全項目の値)の取得に関して、上記のコードは「一回のバリエーションチェックに、一行のデータのみチェックする」という想定ですが、
以前書いたブログのように、一回で複数行のデータをチェックしたい場合はこのように書き換えてください~
item = self.root_document[self.document_path[0]][self.document_path[1]]
そして、バリエーションチェックのコードを紹介します~
スキーマの中に、さきほど作ったチェック条件を入れました~
from cerberus import Validator
from customized_validator import CustomizedValidator
SCHEMA = {
'name': {
'type': 'string',
'required': True,
},
'nickName': {
'type': 'string',
'required': True,
'true_either_or': 'name', # ここが自作チェック条件
},
}
def validate_info(info):
validator = CustomizedValidator(allow_unknown=True)
if not validator.validate(info, SCHEMA):
print(validator.errors)
return False
return True
# 正常時
info = {'name': 'satoh', 'nickName': 'S'}
print(validate_info(info))
# 異常時、両方とも中身がブランクである場合
info = {'name': '', 'nickName': ''}
print(validate_info(info))
終わりに
Cerberusのもともとあるチェックは便利ですが、PJの要望によってどうしても足りない場合があるかと思います
今回はその自作チェック方法の作り方を調べました。必要な方は活用してください~