For questions:
import sys; print(sys.version): Python 3.7.3import pydantic; print(pydantic.VERSION): 0.23I have a model component which is a polymorphic class for class : Device, VRF, Vlan, Interface and others.
declared as below in SQLAlchemy
class Component(Base):
__tablename__ = "component"
id = Column(Integer, primary_key=True, index=True)
discriminator = Column(String)
__mapper_args__ = {
"polymorphic_on": discriminator,
'with_polymorphic': '*'
}
class Device(Component):
__tablename__ = "device"
id = Column(Integer, ForeignKey(Component.id), primary_key=True)
fqdn = Column(String, index=True)
name = Column(String, unique=True, index=True)
role = Column(Enum(RoleEnum), nullable=False)
type = Column(Enum(TypeEnum), nullable=False)
serial = Column(String, unique=True)
version = Column(String)
management_ip = Column(String, unique=True)
brand_id = Column(Integer, ForeignKey("brand.id"))
location_id = Column(Integer, ForeignKey("location.id"))
owner_id = Column(Integer, ForeignKey("customer.id"))
brand = relationship("Brand")
location = relationship("Location")
owner = relationship("Customer")
created_at = Column(DateTime, default=datetime.datetime.now)
updated_at = Column(DateTime, default=datetime.datetime.now)
__mapper_args__ = {
'polymorphic_load': 'selectin',
"polymorphic_identity": "Device"
}
def __repr__(self):
return "<Device(id='%d', name='%s', fqdn='%s')>" % (
self.id,
self.name,
self.fqdn,
)
class Interface(Component):
__tablename__ = "interface"
id = Column(Integer, ForeignKey(Component.id), primary_key=True)
name = Column(String, index=True)
description = Column(String)
role = Column(Enum(RoleEnum), nullable=False)
ip_address_id = Column(Integer, ForeignKey("ip_address.id"))
ip_address = relationship("Ip_Address")
# infrastructures = relationship("InfrastructureInterface")
created_at = Column(DateTime, default=datetime.datetime.now)
updated_at = Column(DateTime, default=datetime.datetime.now)
__mapper_args__ = {
'polymorphic_load': 'selectin',
"polymorphic_identity": "Interface"
}
def __repr__(self):
return "<Interface(id='%d', name='%s', role='%s')>" % (
self.id if self.id is not None else 0,
self.name,
self.role,
)
...
in Pydantic Model: I would like to have a class component which could receive any of Class
currently I did that:
# Additional properties to return via API
class Infrastructure(InfrastructureBaseInDB):
components: Optional[List[Union[DeviceBase, VRFBase, VlanBase, PeerBase, InterfaceBase]]] = None
Pydantic manage all my object but with the same class not in polymorphic, so it use DeviceBase
result is bad (Part)
"components": [
{
"fqdn": "mydevice.int.name.com",
"name": "mydevice",
"role": "none",
"type": "router",
"serial": "mydevice",
"version": "",
"brand": null,
"location": null,
"owner": null
},
{
"fqdn": null,
"name": "WAN_VRF",
"role": "wan",
"type": null,
"serial": null,
"version": null,
"brand": null,
"location": null,
"owner": null
},
{
"fqdn": null,
"name": "ITFW_N1_TO_N1",
"role": null,
"type": null,
"serial": null,
"version": null,
"brand": null,
"location": null,
"owner": null
},
Do you know how to have many models in the same list ?
Thanks in advance,
@meandus the models (classes) in the Union are checked in order. So, if you put first a model that has fewer properties but still matches, it will be used. Discarding the other models.
So, you should put the most specific models first (the ones with more required attributes).
thanks for answering @tiangolo
@tiangolo @samuelcolvin this one was a tricky one to figure out and if done incorrectly breaks the provided values, e.g.:
import uuid
from typing import Union
from pydantic import BaseModel
class Something(BaseModel):
id: Union[int, str, uuid.UUID]
type: str
obj = Something(id=uuid.uuid4(), type="something")
# >>> obj
# <Something id=298701003283496140679204034245714674497 type='something'>
class SomethingRight(BaseModel):
id: Union[uuid.UUID, int, str]
type: str
obj_right = SomethingRight(id=uuid.uuid4(), type="something_right")
# >>> obj_right
# <SomethingRight id=UUID('56452b0f-c03a-429a-b318-16a528505baa') type='something_right'>
Would it be possible to document this behaviour cause as you can see the UUID was converted to it int representation?
I think it is documented, but is love a PR to make it clearer.
@samuelcolvin would be happy to prep a PR, is there some section in the doco you'd like it under or should i make a Gotchas section under index.rst?
Humm, I don't really like faq/gotcha sections they end up as a bin for unstructured content.
Best to add a dedicated "Union" section somewhere.
You're probs right, will prep now.
Most helpful comment
@meandus the models (classes) in the
Unionare checked in order. So, if you put first a model that has fewer properties but still matches, it will be used. Discarding the other models.So, you should put the most specific models first (the ones with more required attributes).