FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Support hybrid_property, column_property, declared_attr by 50Bytes-dev · Pull Request #801 · fastapi/sqlmodel · GitHub

Repository navigation

Support hybrid_property, column_property, declared_attr - #801

Open
50Bytes-dev wants to merge 66 commits into
fastapi:mainfrom
50Bytes-dev:main
Open

50Bytes-dev wants to merge 66 commits into
fastapi:mainfrom
50Bytes-dev:main

Conversation

Copy link
Copy Markdown
    class Item(SQLModel, table=True):
        id: Optional[int] = Field(default=None, primary_key=True)
        value: float
        hero_id: int = Field(foreign_key="hero.id")
        hero: "Hero" = Relationship(back_populates="items")

    class Hero(SQLModel, table=True):
        id: Optional[int] = Field(default=None, primary_key=True)
        name: str
        items: list[Item] = Relationship(back_populates="hero")

        @hybrid_property
        def total_items(self):
            return sum([item.value for item in self.items], 0)

        @total_items.inplace.expression
        @classmethod
        def _total_items_expression(cls):
            return (
                select(func.coalesce(func.sum(Item.value), 0))
                .where(Item.hero_id == cls.id)
                .correlate(cls)
                .label("total_items")
            )

        @hybrid_property
        def status(self):
            return "active" if self.total_items > 0 else "inactive"

        @status.inplace.expression
        @classmethod
        def _status_expression(cls):
            return (
                select(case((cls.total_items > 0, "active"), else_="inactive"))
                .label("status")
            )

50Bytes-dev changed the title Support hybrid_property Support hybrid_property, column_property, declared_attr Mar 1, 2024

Copy link
Copy Markdown
Author
    class Item(SQLModel, table=True):
        id: Optional[int] = Field(default=None, primary_key=True)
        value: float
        hero_id: int = Field(foreign_key="hero.id")
        hero: "Hero" = Relationship(back_populates="items")

    class Hero(SQLModel, table=True):
        id: Optional[int] = Field(default=None, primary_key=True)
        name: str
        items: List[Item] = Relationship(back_populates="hero")

        @declared_attr
        def total_items(cls):
            return column_property(cls._total_items_expression())

        @classmethod
        def _total_items_expression(cls):
            return (
                select(func.coalesce(func.sum(Item.value), 0))
                .where(Item.hero_id == cls.id)
                .correlate_except(Item)
                .label("total_items")
            )

        @declared_attr
        def status(cls):
            return column_property(
                select(
                    case(
                        (cls._total_items_expression() > 0, "active"), else_="inactive"
                    )
                ).scalar_subquery()
            )

awoimbee left a comment •
edited
Loading

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Just small suggestions from a random outsider :p (some suggestions might be wrong).
All in all, this is clean and adds a lot of functionality, thanks !
You should look into this @tiangolo !

Comment thread sqlmodel/main.py Outdated
Comment thread sqlmodel/main.py Outdated
Comment thread sqlmodel/main.py
Comment thread sqlmodel/main.py Outdated
50Bytes-dev and others added 3 commits March 7, 2024 17:18
Co-authored-by: Arthur Woimbée <arthur.woimbee@gmail.com>
Co-authored-by: Arthur Woimbée <arthur.woimbee@gmail.com>
Co-authored-by: Arthur Woimbée <arthur.woimbee@gmail.com>

Copy link
Copy Markdown

Please merge it asap :3. I need it, lol.

Copy link
Copy Markdown

hey can we get this merged in

mfkaroui commented Apr 4, 2024

Copy link
Copy Markdown

@tiangolo Could you please take a look at this MR. The functionality is very nice. Would be a nice addition. Doesn't seem to clash with overall design

Copy link
Copy Markdown
    class Item(SQLModel, table=True):
        id: Optional[int] = Field(default=None, primary_key=True)
        value: float
        hero_id: int = Field(foreign_key="hero.id")
        hero: "Hero" = Relationship(back_populates="items")

    class Hero(SQLModel, table=True):
        id: Optional[int] = Field(default=None, primary_key=True)
        name: str
        items: List[Item] = Relationship(back_populates="hero")

        @declared_attr
        def total_items(cls):
            return column_property(cls._total_items_expression())

        @classmethod
        def _total_items_expression(cls):
            return (
                select(func.coalesce(func.sum(Item.value), 0))
                .where(Item.hero_id == cls.id)
                .correlate_except(Item)
                .label("total_items")
            )

        @declared_attr
        def status(cls):
            return column_property(
                select(
                    case(
                        (cls._total_items_expression() > 0, "active"), else_="inactive"
                    )
                ).scalar_subquery()
            )

Following this example I am getting

pydantic.errors.PydanticUserError: A non-annotated attribute was detected: `total_items = <sqlalchemy.orm.decl_api.declared_attr object at 0x10e415350>`. All model fields require a type annotation; if `total_items` is not meant to be a field, you may be able to resolve this error by annotating it as a `ClassVar` or updating `model_config['ignored_types']`.

Even if I do def total_items(cls): -> int I still get the same error.
SQLModel version 0.0.16

But I think we can get the same result with computed_field and the property decorator

    from pydantic import computed_field

    class Hero(SQLModel, table=True):
        id: Optional[int] = Field(default=None, primary_key=True)
        name: str
        items: List[Item] = Relationship(back_populates="hero")

        @computed_field
        @property
        def total_items(cls) -> int:
            return len(self.items)

Copy link
Copy Markdown

Any movement to get this functionality in?

sakost commented Aug 25, 2025

Copy link
Copy Markdown

any updates on this?

github-actions Bot added the conflicts Automatically generated when a PR has a merge conflict label Sep 5, 2025

github-actions Bot commented Sep 5, 2025

Copy link
Copy Markdown
Contributor

This pull request has a merge conflict that needs to be resolved.

Vizonex commented Sep 25, 2025

Copy link
Copy Markdown

I think I can go a bit further than what this pr had in mind. I was thinking about combining computed_feilds and hybrid_property column_property and declared_attr together. Does anyone have any tips and suggestions? I'll try and use what this pr had in mind as a blueprint.

…configuration and utility functions for SQLModel

Vizonex commented Oct 22, 2025

Copy link
Copy Markdown

@50Bytes-dev Glad to see your pr is still alive, mind if I help you review it?

…columns by schema; update col function to return InstrumentedAttribute for better type safety

Vizonex commented Nov 21, 2025

Copy link
Copy Markdown

@50Bytes-dev Have you tried adding some tests to the pytest to ensure that this implementation works?

Copy link
Copy Markdown
Author

@50Bytes-dev Have you tried adding some tests to the pytest to ensure that this implementation works?

Yes, I have basic tests. I use this PR in the production of my projects and make sure that everything works correctly.

tstorek commented Nov 26, 2025

Copy link
Copy Markdown

@50Bytes-dev thanks, for that piece of code. Is there any chance for release some time soon. I have a use case starting from next week and I'd like to omit a vanilla sqlalchemy workaround :)

Copy link
Copy Markdown
Author

@50Bytes-dev thanks, for that piece of code. Is there any chance for release some time soon. I have a use case starting from next week and I'd like to omit a vanilla sqlalchemy workaround :)

Release where? Personally, I just use the repository and don't plan to release anything anywhere. I recommend trying it this way too, it's quite convenient.

dependencies = [
  "sqlmodel",
]

[tool.uv.sources]
sqlmodel = { git = "https://github.com/50Bytes-dev/sqlmodel.git", rev = "833b8700e5006177d1a57fd8b3109bd625a358de" }

tstorek commented Nov 26, 2025 •
edited
Loading

Copy link
Copy Markdown

@50Bytes-dev Okay, sorry. I thought that the PR is meant to be merged at some point.

Copy link
Copy Markdown
Author

@50Bytes-dev Okay, sorry. I thought that the PR is meant to be merged at some point.

I think that the main repository is dead and unlikely to be developed further, so I created my own fork where I implement all the necessary functions myself.

ksaadDE commented Jan 15, 2026

Copy link
Copy Markdown

I think that the main repository is dead

The main repo of what? FastAPI, SQLmodel?

If there is no PR, in SQLModel I assume, nobody can check it, thus it appears obv. dead. Though if you look at the commit history in main, all is fine

Looking for a method to introduce calculated column easily. Got to this to just read that lol

This branch has not been deployed

No deployments
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

conflicts Automatically generated when a PR has a merge conflict feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.


Back | FazBrowse Home | New Git URL