@@ -91,15 +91,15 @@ async def create(cls, **data: typing.Any) -> typing.Self:
9191 async with _get_client () as client :
9292 response = await client .create (cls ._typename , aliased_data )
9393 uid = response .json ()["id" ]
94- return cls ( ** aliased_data , ** { BubbleField .ID : uid })
94+ return cls . model_validate ({ ** aliased_data , BubbleField .ID : uid })
9595
9696 @classmethod
9797 async def get (cls , uid : str ) -> typing .Self | None :
9898 """Retrieve a single thing by its unique ID."""
9999 async with _get_client () as client :
100100 try :
101101 response = await client .retrieve (cls ._typename , uid )
102- return cls ( ** response .json ()["response" ])
102+ return cls . model_validate ( response .json ()["response" ])
103103 except BubbleAPIError as e :
104104 if e .status_code == http .HTTPStatus .NOT_FOUND :
105105 return None
@@ -141,6 +141,26 @@ async def delete(self) -> None:
141141 async with _get_client () as client :
142142 await client .delete (self ._typename , self .uid )
143143
144+ async def refresh (self ) -> typing .Self :
145+ """Fetch latest data from Bubble and update this instance in place.
146+
147+ Useful after create_or_update() to get server-computed fields like
148+ Modified Date, or fields set by Bubble workflows.
149+
150+ Returns:
151+ Self, for method chaining.
152+
153+ Raises:
154+ BubbleAPIError: If the record no longer exists (404) or other API error.
155+ """
156+ async with _get_client () as client :
157+ response = await client .retrieve (self ._typename , self .uid )
158+ cls = type (self )
159+ fresh = cls .model_validate (response .json ()["response" ])
160+ for field_name in cls .model_fields :
161+ setattr (self , field_name , getattr (fresh , field_name ))
162+ return self
163+
144164 @classmethod
145165 async def find (
146166 cls ,
@@ -178,7 +198,7 @@ async def find(
178198 exclude_remaining = exclude_remaining ,
179199 additional_sort_fields = additional_sort_fields ,
180200 )
181- return [cls ( ** item ) for item in response .json ()["response" ]["results" ]]
201+ return [cls . model_validate ( item ) for item in response .json ()["response" ]["results" ]]
182202
183203 @classmethod
184204 async def find_iter (
@@ -205,7 +225,7 @@ async def find_iter(
205225 )
206226 body = response .json ()["response" ]
207227 for item in body ["results" ]:
208- yield cls ( ** item )
228+ yield cls . model_validate ( item )
209229 if body ["remaining" ] == 0 :
210230 break
211231 cursor += len (body ["results" ])
@@ -273,4 +293,5 @@ async def create_or_update(
273293 # construct instance from aliased data
274294 # server-side fields like Modified Date won't be populated
275295 instance_data = (aliased_create_data or {}) if result ["created" ] else (aliased_update_data or {})
276- return cls (** aliased_match , ** instance_data , ** {BubbleField .ID : result ["uids" ][0 ]}), result ["created" ]
296+ model_data = {** aliased_match , ** instance_data , BubbleField .ID : result ["uids" ][0 ]}
297+ return cls .model_validate (model_data ), result ["created" ]
0 commit comments