Alena Poliakova
Alena Poliakova

Reputation: 111

pydantic: how to make a choice of types for a field?

I have a FastAPI app and I need to create a Car class in which the attributes wheel and speed can take an int or str type. How to do it? This code does not work, because wheel and speed will have only an integer type (not str in second print):

from pydantic import BaseModel


class Car(BaseModel):
    wheel: int | str
    speed: int | str


bmw = Car(wheel=4, speed=250)
mercedes = Car(wheel='4', speed='200')

print(type(bmw.wheel), type(bmw.speed))
print(type(mercedes.wheel), type(mercedes.speed))

Result is:

<class 'int'> <class 'int'>
<class 'int'> <class 'int'>

Upvotes: 1

Views: 2941

Answers (3)

Buffcoder
Buffcoder

Reputation: 63

What you are looking for is the Union option from typing. An example is below

from typing import Union
from pydantic import BaseModel

class Car(BaseModel):
    wheel: Union[str,int]
    speed: Union[str,int]

Further, instead of simple str or int you can write your own classes for those types in pydantic and add more attributes as needed.

Upvotes: -1

juanpa.arrivillaga
juanpa.arrivillaga

Reputation: 95948

So, I would personally just use pydantic.StrictInt and pydantic.StricStr here (and actually, I use those almost everywhere, particularly StrictStr because practically any object can be coerced to a string):

import pydantic


class Car(pydantic.BaseModel):
    wheel: pydantic.StrictInt | pydantic.StrictStr
    speed: pydantic.StrictInt | pydantic.StrictStr


bmw = Car(wheel=4, speed=250)
mercedes = Car(wheel='4', speed='200')

print(type(bmw.wheel), type(bmw.speed))
print(type(mercedes.wheel), type(mercedes.speed))

This prints:

<class 'int'> <class 'int'>
<class 'str'> <class 'str'>

Upvotes: 5

Michael Ruth
Michael Ruth

Reputation: 3504

There is order in the type specification. With int | str, the value will be treated as an int if possible, otherwise a str. Reversing the order str | int will result in the values being treated as str if possible, otherwise int. The problem with reversing the order is that pretty much everything can be treated as a str so the bmw values will be cast to str. Example:

from pydantic import BaseModel


class Car(BaseModel):
    wheel: str | int
    speed: str | int


bmw = Car(wheel=4, speed=250)
mercedes = Car(wheel='4', speed='200')

print(type(bmw.wheel), type(bmw.speed))
print(type(mercedes.wheel), type(mercedes.speed))
<class 'str'> <class 'str'>
<class 'str'> <class 'str'>

The key here is that you need to choose which type takes precedence.

Upvotes: 0

Related Questions