Как указать в модели для поля возможность значения как string так и null?

Рейтинг: 1Ответов: 2Опубликовано: 05.04.2023

Пробовал как в документации, но это не работает https://field-idempotency--pydantic-docs.netlify.app/usage/types/ В итоговой схеме json, нет никаких инструкций насчёт того что поле может принимать значение null и string. Максимум чего я добился - игнорирование ошибки если поля нет в принципе. Вот что я пытался сделать:

none_or_str: str
none_or_str: str | None
none_or_str: Optional[str] = ...
none_or_str: str = Field(...)

Код для воспроизведения проблемы:

from typing import TypedDict, Optional
from pydantic import BaseModel, Field
import json
from jsonschema import validate
            
def validate_schema(instance: dict, schema: dict) -> None:
    validate(instance=instance, schema=schema)
                
                
class TTest(BaseModel):
    none_or_str: Optional[str] = None
                
j = '''{"none_or_str":null}'''
validate_schema(json.loads(j), TTest.schema())

Ошибка:

jsonschema.exceptions.ValidationError: None is not of type 'string'

Failed validating 'type' in schema['properties']['none_or_str']:
    {'title': 'None Or Str', 'type': 'string'}

On instance['none_or_str']:
    None

Ответы

▲ 2Принят

Похоже, что генерация схемы исправлена в будущей версии pydantic 2.*
(сейчас можно установить через pip install --pre -U "pydantic>=2.0a1"):

import json

from typing import Optional
from pydantic import BaseModel
from jsonschema import validate


class TTest(BaseModel):
    none_or_str: Optional[str] = None


print(TTest.schema_json(indent=2))
# Вывод:
# {
#   "title": "TTest",
#   "type": "object",
#   "properties": {
#     "none_or_str": {
#       "anyOf": [
#         {
#           "type": "string"
#         },
#         {
#           "type": "null"
#         }
#       ],
#       "default": null,
#       "title": "None Or Str"
#     }
#   }
# }


def validate_schema(instance: dict, schema: dict) -> None:
    validate(instance=instance, schema=schema)


j = '''{"none_or_str":null}'''
validate_schema(json.loads(j), TTest.schema())  # Без ошибок

j = '''{"none_or_str":123}'''
validate_schema(json.loads(j), TTest.schema())  # Ошибка валидации 
▲ 1

Сделал костыль. Без проверки на конкретное поле, как временное решение.

import json
import jsonschema
from jsonschema import validate
def validate_schema(instance: dict, schema: dict) -> None:
    try:
        validate(instance=instance, schema=schema)
    except jsonschema.exceptions.ValidationError as e:
        if "None is not of type 'string'" in str(e) and 'null_crunch' in str(e):
            print('Validation pass, because have option null_crunch')
            pass
        else:
            raise jsonschema.exceptions.ValidationError

class TTest(BaseModel):
    none_or_str: Optional[str] = Field(..., null_crunch=True)

j = '''{"none_or_str":null}'''
validate_schema(json.loads(j), TTest.schema())