-
-
Notifications
You must be signed in to change notification settings - Fork 733
Pydantic.PrivateAttr default
and default_factory
are ignored by SQLModel
#149
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
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' |
Any solution for this? I just ran into the same problem |
It appears that we are missing private attribute initialization. I have raised a PR to fix this. |
Great! I ended up adding 8 columns to my SQL table because of this bug.., finally able to clean up after this merge |
same issue here |
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 subscriptable The 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._anonymous If 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 |
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. |
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) |
First Check
Commit to Help
Example Code
Description
As far as I can tell SQLModel is ignoring the
default
anddefault_factory
parameters 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
The text was updated successfully, but these errors were encountered: