1

Consider the following model:


from datetime import datetime
from typing import Optional, Tuple

from sqlalchemy.dialects.postgresql import TSTZRANGE
from sqlalchemy import Column
from sqlmodel import Field, SQLModel


class DateRange(SQLModel):
    """Plan rate model"""

    id: Optional[int] = Field(default=None, primary_key=True)

    ts_range: Tuple[datetime, datetime] = Field(nullable=False, sa_column=Column(TSTZRANGE))

I am sucessfully able to add data to the database (using fastAPI). However, as mentioned below, when trying to return the newly added object, ie, since ts_range is of type Range, it is unable to serialize the response while returning.


@router.post(
    "/rates",
    tags=["rates", "create"],
    response_model=DateRange,
)
async def create_rate(
    plan_id: int,
    rate: DateRange,
    db: DB = Depends(get_db),
) -> DateRange:
    """Create new rate"""

    rate = DateRange(**rate.dict())
    db.add(rate)
    try:
        await db.commit()
        await db.refresh(rate)
        print(rate)  # NOTE: it works until this point
        return rate  # FIXME: serialization issue
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Invalid date range [{e}]",
        )

Pratik K.
  • 147
  • 2
  • 13
  • Since there is no native `range` type in JSON - what do you want to return it as? You can add custom types through pydantic's custom types: https://docs.pydantic.dev/latest/usage/types/custom/ – MatsLindh Aug 07 '23 at 20:29
  • As mentioned in the schema, Ideally I want to be able to add a simple parser/serializer function along the lines of: `lambda x: (x.lower, x.upper)`, ie convert from `Range` to `Tuple[datetime, datetime]` – Pratik K. Aug 07 '23 at 22:32
  • I'm not familiar enough with SQLModel to say whether you can do it in a single statement in the model definition, but using a custom type for your response model would usually be the way to solve that. – MatsLindh Aug 08 '23 at 10:15
  • `SQLModel` in this case is analogous to just `Base` from sqlalchemy. as shown above the custom type approach is what I tried, but the serialization is response is not working. I was hoping there is a way to just declare a decorated function or the like to specify the serialization as `lambda ts: [ts.lower, ts.upper]` since that is the representation of `Range` received from db – Pratik K. Aug 09 '23 at 10:08
  • It has little to do with `SQLModel` and more to do with `pydantic BaseModel` and sqlalchemy `Base = declarative_base()` – Pratik K. Aug 09 '23 at 10:10
  • I couldn't get this to work, but perhaps you can https://github.com/tiangolo/sqlmodel/issues/235. – snakecharmerb Aug 15 '23 at 13:35
  • Neither could I :( – Pratik K. Aug 19 '23 at 14:27

0 Answers0