sqlmodel
sqlmodel copied to clipboard
Adding _init_private_attributes to SQLModel __init__ function.
Fixing:
Private attributes cannot be used in SQLModel. Attributes initialized with PrivateAttr
cannot be found.
Proposed solution:
Add a missing line from Pydantic source code.
Note: the class method from_orm does have this initialization.
Related issues:
https://github.com/tiangolo/sqlmodel/issues/149 mentions this issue
Disclaimer
This is my first-ever contribution to an open-source project. I would appreciate any kind of feedback.
π Docs preview for commit 7a2b7af7b98f8d0e4722b7792acae10ddf9a9996 at: https://63519cbbc2f8c40065737d3f--sqlmodel.netlify.app
Codecov Report
Base: 98.49% // Head: 98.50% // Increases project coverage by +0.00%
:tada:
Coverage data is based on head (
7a2b7af
) compared to base (ea79c47
). Patch coverage: 100.00% of modified lines in pull request are covered.
:exclamation: Current head 7a2b7af differs from pull request most recent head 844e21c. Consider uploading reports for the commit 844e21c to get more accurate results
Additional details and impacted files
@@ Coverage Diff @@
## main #472 +/- ##
=======================================
Coverage 98.49% 98.50%
=======================================
Files 185 186 +1
Lines 5856 5867 +11
=======================================
+ Hits 5768 5779 +11
Misses 88 88
Impacted Files | Coverage Ξ | |
---|---|---|
tests/test_private_attributes.py | 100.00% <100.00%> (ΓΈ) |
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.
:umbrella: View full report at Codecov.
:loudspeaker: Do you have feedback about the report comment? Let us know in this issue.
Thanks for the fix! I've used it as a workaround in my project by adding it to the init method of my own model.
I noticed that when I loaded a model from the database the private attributes were not initialized because the init in SQLModel is not called. I had to call it separately on the model before being able to use the private attribute.
Have you tested whether your fix works when loading a model from the database?
Thanks for the fix! I've used it as a workaround in my project by adding it to the init method of my own model.
I noticed that when I loaded a model from the database the private attributes were not initialized because the init in SQLModel is not called. I had to call it separately on the model before being able to use the private attribute.
Have you tested whether your fix works when loading a model from the database?
Do you mean in an example such as the one below?
test_id = uuid4()
class Hero(SQLModel, table=True):
id: UUID = Field(default_factory=uuid4, primary_key=True)
_private_hero_attribute: str = PrivateAttr(default="private hero value")
metadata = MetaData()
with Session(engine) as session:
hero_rusty_man = Hero(
id=test_id,
)
session.add(hero_rusty_man)
session.commit()
with Session(engine) as session:
statement = select(Hero).where(Hero.id == test_id)
hero = session.exec(statement).scalars().first()
assert hero._private_hero_attribute == "private hero value" # this fails
hero = Hero.from_orm(hero)
assert hero._private_hero_attribute == "private hero value" # this doesn't fail
Indeed, when running SQLAlchemy, the private attributes don't get correctly initialized. Calling the method from_orm solves the problem for this particular case. Not ideal.
I haven't figured out if there is a way to "automate" this process. Maybe SQLAlchemy is using another init/factory_function?
π Docs preview for commit 844e21c717746da87e2fc4be0e7efa804b8cbce6 at: https://639ce0b204318b01e2823f64--sqlmodel.netlify.app
Whats the status of this?
Any chance we can get this merged?
@lucas-labs the reality is that the fix doesn't fully work, as shown in https://github.com/tiangolo/sqlmodel/pull/472#issuecomment-1301647570
Calling the method from_orm solves the problem for this particular case. Not ideal.
This is the way this works in Pydantic; the method is called from init,
from_orm
, and construct
; we need to call it from any place where initialization is required. Could you release this fix? We have the entire infrastructure from a base model from where all objects inherit from a BaseModel to make it much simpler to handle connections. Still, without the ability to use private attributes, this makes it impossible to handle.
I imagine this is the case for many users since a model that represents a database object might need to have more often attributes that do not necessary link to the database itself and are used for internal logic.
I think I am also running into this issue. I am retrieving an object from the database and want to copy it like described in the fastapi docs for partial updates.
object_from_db = session.exec(select_cmd).one_or_none()
copied_object = object_from_db.model_copy()
The model_copy results in the following error:
object has no attribute '__pydantic_extra__'. Did you mean: '__pydantic_private__'?
Is there a workaround I can use?