I've got 3 database models; Graphs, Nodes and Paths. Graphs have nodes and nodes have paths and paths have destination and source nodes. Here is the models (I am using ormar ORM):
class Graph(BaseModel):
"""Model for Graph objects."""
class Meta(BaseMeta):
tablename = "graphs"
id: int = ormar.BigInteger(primary_key=True)
name: str = ormar.String(max_length=MAX_NAME_SIZE, unique=True)
code: str = ormar.String(max_length=MAX_CODE_SIZE, unique=True)
class Node(BaseModel):
"""Model for Node objects."""
class Meta(BaseMeta):
tablename = "nodes"
id: int = ormar.BigInteger(primary_key=True)
header: str = ormar.String(max_length=MAX_CHAR_VAR_SIZE)
body: str = ormar.Text(nullable=True)
graph: Graph = ormar.ForeignKey(
Graph,
nullable=False,
ondelete="CASCADE",
)
class Path(BaseModel):
"""Model for Path objects."""
class Meta(BaseMeta):
tablename = "paths"
id: int = ormar.BigInteger(primary_key=True)
kind: str = ormar.Text(nullable=False)
context: str = ormar.Text(nullable=False)
source: Node = ormar.ForeignKey(
Node,
nullable=False,
ondelete="CASCADE",
related_name="source_paths",
)
destination: Node = ormar.ForeignKey(
Node,
nullable=False,
ondelete="CASCADE",
related_name="destination_paths",
)
What I want to do is create an endpoint that response the graph data with nested node and path information like this:
{
"id": 28,
"name": "test",
"code": "abc",
"nodes": [
{
"id": 18,
"header": "lorem",
"body": "ipsum",
"paths": [
{
"destination_id": 19,
"kind": "SELECT",
"context": "SOME TEXT"
}
]
}
}
I have queried the Graph object like this:
await Graph.objects.select_related("nodes__destination_paths__destination").get(id=graph_id)
and have some pydantic models to create response:
class PathResponse(BaseModel):
destination_id: int
kind: PathKindEnum
context: str
@root_validator
def set_destination_id(cls, values):
# values = {'kind': '...', 'context': 'testing'}
values["destination_id"] = values["destination"].id
class Config:
orm_mode = True
allow_population_by_field_name = True
use_enum_values = True
class NodeResponse(BaseModel):
id: int
header: str
body: str
paths: list[PathResponse] = []
class Config:
orm_mode = True
allow_population_by_field_name = True
use_enum_values = True
fields = {"paths": {"alias": "destination_paths"}}
class GraphResponse(BaseModel):
id: int
name: str
code: str
nodes: list[NodeResponse] = []
class Config:
orm_mode = True
allow_population_by_field_name = True
use_enum_values = True
fields = {"nodes": {"alias": "graph_nodes"}}
When I make the request, I got the error:
File "/app_path/web/api/graphs/schema.py", line 69, in set_destination_id
values["destination_id"] = values["destination"].id
│ └ {'kind': 'BUTTON', 'context': 'testing'}
└ {'kind': 'BUTTON', 'context': 'testing'}
KeyError: 'destination'
destination
object is missing in the dict but I have no idea how to add this information. I think my query can be wrong so I've also try
return await Graph.objects.select_related(
["nodes", "nodes__source_paths", "nodes__destination_paths"],
).get(id=graph_id)
but that did not work either. What am I missing here?