Skip to content

Commit d78fc71

Browse files
committed
Add notes on Pydantic implementation of updated_at
1 parent 01ca385 commit d78fc71

1 file changed

Lines changed: 43 additions & 0 deletions

File tree

docs/advanced/sa-column.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,46 @@ The `updated_at` column has an `onupdate` value of `func.now()`, this means that
3131
```
3232

3333
</details>
34+
35+
### Pydantic Implementation
36+
37+
Implementing these timestamps on the DB side with SQLAlchemy works very well as the database itself is what will create and update the fields whenever a relevant database interaction occurs.
38+
39+
It's possible to achieve similar behaviour with Pydantic, for the `created_at` timestamp by using a Pydantic `Field` with a `default_factory`:
40+
41+
```python
42+
from datetime import datetime
43+
44+
from pydantic import BaseModel, Field
45+
46+
47+
class Model(BaseModel):
48+
created_at: datetime = Field(default_factory=datetime.utcnow)
49+
50+
51+
m1 = Model()
52+
m2 = Model()
53+
print(f'{m1.created_at} != {m2.created_at}')
54+
#> 2022-05-19 10:49:22.053624 != 2022-05-19 10:49:22.053641
55+
```
56+
57+
Another approach is to use a Pydantic `validator`:
58+
59+
```python
60+
from datetime import datetime
61+
62+
from pydantic import BaseModel, validator
63+
64+
class Model(BaseModel):
65+
created_at: datetime = None
66+
67+
@validator('ts', pre=True, always=True)
68+
def set_created_at_now(cls, v):
69+
return v or datetime.now()
70+
```
71+
72+
Both of these approaches come with the major caveat that default fields are set during the **Pydantic model instantiation**, as opposed to during **interactions with the database**, instead of the SQLModel approach which sets it with `server_default` which means that the timestamp will be exactly when the row is created in the database.
73+
74+
The real issue starts when looking at the `updated_at` timestamp - SQLAlchemy has the `onupdate` default which runs a function when the row is updated in the database, but there is no easy way to do this in Pydantic as it has no concept of 'about to be saved'.
75+
76+
So the pure Pydantic approach would require some additional logic to always change the `updated_at` timestamp before doing a write to the database, which adds some more complexity to the code and does not have benefits over the SQLAlchemy approach.

0 commit comments

Comments
 (0)