1

I am using a Python and SQLAlchemy to perform CRUD operations on my oracle database.

I have the below models:

class ServiceOrderModel(BaseModel):
    service_order_id: int | None = None
    service_order_number: str | None = None
    service_type: str
    service_order_items: Optional[List[ServiceOrderItemModel]] = None

    class Config:
        from_attributes = True

class ServiceOrderItemModel(BaseModel):
    service_order_item_id: Optional[int] = None
    service_order_id: Optional[int] = None
    component_id: Optional[int] = None
    component: Optional[ComponentModel] = None
    total_qty: Optional[float]
    unit_price: Optional[float]
    service_order_items_received: Optional[List[ServiceOrderItemReceiveModel]] = None

    class Config:
        from_attributes = True


class ComponentModel(BaseModel):
    component_id: Optional[int] = None
    component_serial_number: str = None
    component_name: Optional[str] = None

    class Config:
        from_attributes = True

When a user creates a service order they also have to create multiple items (One to many). Each item also has a (One to one) relationship with component.

When I have the ServiceOrderModel, what is the best way to perform an insert into the service_order, service_order_item, and component table with this single object.

Would it be best to split it up? How would I do that as I would need the service_order_id generated from the service_order table to perform an insert into the item table. I have my table def's below as well.

class ServiceOrder(BaseModel):
    __tablename__ = "service_order"

    service_order_id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
    service_order_number: Mapped[Optional[str]] = mapped_column(
        String(42),
        server_default=text(
            """
    CASE "SERVICE_TYPE" 
        WHEN 'NEW' THEN 'SO'||TO_CHAR("SERVICE_ORDER_ID") 
        WHEN 'REPAIR' THEN 'RO'||TO_CHAR("SERVICE_ORDER_ID") 
        ELSE NULL 
    END
"""
        ),
    )
    service_type: Mapped[str] = mapped_column(String(50))
    service_order_item: Mapped[List["ServiceOrderItem"]] = relationship(
        "ServiceOrderItem", back_populates="service_order"
    )


class ServiceOrderItem(BaseModel):
    __tablename__ = "service_order_item"

    service_order_item_id: Mapped[int] = mapped_column(
        primary_key=True, autoincrement=True
    )
    component_id: Mapped[Optional[int]] = mapped_column(
        ForeignKey("component.component_id")
    )
    service_order_id: Mapped[int] = mapped_column(
        ForeignKey("service_order.service_order_id")
    )
    total_qty: Mapped[Optional[int]]
    unit_price: Mapped[Optional[float]]
    component: Mapped["Component"] = relationship(
        "Component", back_populates="service_order_item"
    )
    service_order: Mapped["ServiceOrder"] = relationship(
        "ServiceOrder", back_populates="service_order_item"
    )


class Component(BaseModel):
    __tablename__ = "component"

    component_id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
    component_name: Mapped[str] = mapped_column(String(500))
    component_serial_number: Mapped[str] = mapped_column(String(250), unique=True)
    service_order_item: Mapped[List["ServiceOrderItem"]] = relationship(
        "ServiceOrderItem", back_populates="component"
    )
0

1 Answer 1

1

I was able to insert all 3 objects with one insert/add statement. Below is the function I created to do this.

async def create_purchase_order(
    session: AsyncSession, new_service_order: CreatePurchaseOrderRequest
) -> ServiceOrderModel:
    async with session:
        service_order_dict = new_service_order.model_dump(by_alias=True)
        service_order_dict["service_order_item"] = [
            DBServiceOrderItem(
                component=DBComponent(**item.pop("component", {})),
                **item,
            )
            if item.get("component")
            else DBServiceOrderItem(
                **item,
            )
            for item in service_order_dict.pop("service_order_items")
        ]

        service_order_orm = DBServiceOrder(**service_order_dict)

        session.add(service_order_orm)
        await session.commit()

        return service_order_orm.service_order_id
Sign up to request clarification or add additional context in comments.

1 Comment

As you are already checking if item has a component key, you can shorten the upper line to component=DBComponent(**item.pop("component")),. You might also want to ensure that 'service_order_item' is in your service_order_dict like this for item in service_order_dict.pop("service_order_items", [])

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.