Replies: 8 comments
-
|
Tried some other options for achieving this, with a pydantic model as the Environment: from typing import Optional
from pydantic import BaseModel, PrivateAttr
from sqlmodel import Field, SQLModel
class A(BaseModel):
some_attr: int = 2
class B1(SQLModel, table=True):
_a: A = PrivateAttr(default_factory=A)
id: Optional[int] = Field(default=None, primary_key=True)
class B2(SQLModel, table=True):
_a: A = PrivateAttr(default=A())
id: Optional[int] = Field(default=None, primary_key=True)
class B3(SQLModel, table=True):
_a: A = PrivateAttr()
id: Optional[int] = Field(default=None, primary_key=True)
# from https://pydantic-docs.helpmanual.io/usage/models/#private-model-attributes
def __init__(self, **data):
super().__init__(**data)
self._a = A()
class B4(SQLModel, table=True):
_a: A = PrivateAttr()
id: Optional[int] = Field(default=None, primary_key=True)
@property
def a(self):
return self._a
for B in [B1, B2, B3, B4]:
b = B()
try:
print(b._a.some_attr)
except Exception as e:
print(e)Result in plain python: 'ModelPrivateAttr' object has no attribute 'some_attr'
'ModelPrivateAttr' object has no attribute 'some_attr'
'ModelPrivateAttr' object has no attribute 'some_attr'
'ModelPrivateAttr' object has no attribute 'some_attr'Result in a notebook: 'ModelPrivateAttr' object has no attribute 'some_attr'
'ModelPrivateAttr' object has no attribute 'some_attr'
2
'ModelPrivateAttr' object has no attribute 'some_attr' |
Beta Was this translation helpful? Give feedback.
-
|
Any solution for this? I just ran into the same problem |
Beta Was this translation helpful? Give feedback.
-
|
It appears that we are missing private attribute initialization. I have raised a PR to fix this. |
Beta Was this translation helpful? Give feedback.
-
|
Great! I ended up adding 8 columns to my SQL table because of this bug.., finally able to clean up after this merge |
Beta Was this translation helpful? Give feedback.
-
|
same issue here |
Beta Was this translation helpful? Give feedback.
-
|
I have a similar related issue. I have a PrivateAttr field on my model so it is not persisted with a public getter for clarity. If I construct the model myself the getter works but if I retrieve from the database with File "/Volumes/Crucial X8/Projects/Portal/.venv/lib/python3.12/site-packages/pydantic/main.py", line 807, in __getattr__
return self.__pydantic_private__[item] # type: ignore
│ │ └ '_anonymous'
│ └ <member '__pydantic_private__' of 'BaseModel' objects>
└ User(id=1, username='testuser')
TypeError: 'NoneType' object is not subscriptableThe model class User(SQLModel, table=True):
__tablename__ = "user"
id: int | None = Field(default=None, primary_key=True, gt=0)
username: str = Field(index=True, max_length=32)
email: str
password: str = Field(repr=False)
superuser: bool = Field(default=False)
_anonymous: bool = PrivateAttr(default=False)
@property
def is_anonymous(self) -> bool:
return self._anonymousIf I change my repository method to the following it works fine. Obviously not a viable solution going forward but serves to prove the point. def find_by_username(self, username: str) -> User | None:
stmt = select(User).where(User.username == username)
result = self.session.exec(stmt)
r = result.one_or_none()
u = User(**r.model_dump())
return u |
Beta Was this translation helpful? Give feedback.
-
Furthermore, if you update the object and add it to the session sqlmodel considers it a new instance entirely and you will see a unique constraint error for the duplicate ID. |
Beta Was this translation helpful? Give feedback.
-
I've worked around this with an event listener from pydantic._internal._model_construction import init_private_attributes
from sqlalchemy import event
from sqlmodel import SQLModel
@event.listens_for(SQLModel, "load", propagate=True)
def receive_load(target: Any, context: Any) -> None:
init_private_attributes(target, None) |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
First Check
Commit to Help
Example Code
Description
As far as I can tell SQLModel is ignoring the
defaultanddefault_factoryparameters ofpydantic.PrivateAttr. The example I've given above reproduces on my system. The output can be seen here:As you can see the field is not set to
None, and instead is an empty instance ofpydantic.fields.ModelPrivateAttr.Operating System
macOS
Operating System Details
No response
SQLModel Version
0.0.4
Python Version
3.9.5
Additional Context
No response
Beta Was this translation helpful? Give feedback.
All reactions