mirror of
https://github.com/fastapi/sqlmodel.git
synced 2025-08-15 10:11:34 +08:00
✨ Add support for Pydantic v2 (while keeping support for v1 if v2 is not available), including initial work by AntonDeMeester (#722)
Co-authored-by: Mohamed Farahat <farahats9@yahoo.com> Co-authored-by: Stefan Borer <stefan.borer@gmail.com> Co-authored-by: Peter Landry <peter.landry@gmail.com> Co-authored-by: Anton De Meester <antondemeester+github@gmail.com>
This commit is contained in:

committed by
GitHub

parent
5b733b348d
commit
fa2f178b8a
@ -175,15 +175,17 @@ Now we use the type annotation `HeroCreate` for the request JSON data in the `he
|
||||
# Code below omitted 👇
|
||||
```
|
||||
|
||||
Then we create a new `Hero` (this is the actual **table** model that saves things to the database) using `Hero.from_orm()`.
|
||||
Then we create a new `Hero` (this is the actual **table** model that saves things to the database) using `Hero.model_validate()`.
|
||||
|
||||
The method `.from_orm()` reads data from another object with attributes and creates a new instance of this class, in this case `Hero`.
|
||||
The method `.model_validate()` reads data from another object with attributes (or a dict) and creates a new instance of this class, in this case `Hero`.
|
||||
|
||||
The alternative is `Hero.parse_obj()` that reads data from a dictionary.
|
||||
In this case, we have a `HeroCreate` instance in the `hero` variable. This is an object with attributes, so we use `.model_validate()` to read those attributes.
|
||||
|
||||
But as in this case, we have a `HeroCreate` instance in the `hero` variable. This is an object with attributes, so we use `.from_orm()` to read those attributes.
|
||||
/// tip
|
||||
In versions of **SQLModel** before `0.0.14` you would use the method `.from_orm()`, but it is now deprecated and you should use `.model_validate()` instead.
|
||||
///
|
||||
|
||||
With this, we create a new `Hero` instance (the one for the database) and put it in the variable `db_hero` from the data in the `hero` variable that is the `HeroCreate` instance we received from the request.
|
||||
We can now create a new `Hero` instance (the one for the database) and put it in the variable `db_hero` from the data in the `hero` variable that is the `HeroCreate` instance we received from the request.
|
||||
|
||||
```Python hl_lines="3"
|
||||
# Code above omitted 👆
|
||||
|
@ -90,7 +90,7 @@ So, we need to read the hero from the database, with the **same logic** we used
|
||||
|
||||
The `HeroUpdate` model has all the fields with **default values**, because they all have defaults, they are all optional, which is what we want.
|
||||
|
||||
But that also means that if we just call `hero.dict()` we will get a dictionary that could potentially have several or all of those values with their defaults, for example:
|
||||
But that also means that if we just call `hero.model_dump()` we will get a dictionary that could potentially have several or all of those values with their defaults, for example:
|
||||
|
||||
```Python
|
||||
{
|
||||
@ -102,7 +102,7 @@ But that also means that if we just call `hero.dict()` we will get a dictionary
|
||||
|
||||
And then, if we update the hero in the database with this data, we would be removing any existing values, and that's probably **not what the client intended**.
|
||||
|
||||
But fortunately Pydantic models (and so SQLModel models) have a parameter we can pass to the `.dict()` method for that: `exclude_unset=True`.
|
||||
But fortunately Pydantic models (and so SQLModel models) have a parameter we can pass to the `.model_dump()` method for that: `exclude_unset=True`.
|
||||
|
||||
This tells Pydantic to **not include** the values that were **not sent** by the client. Saying it another way, it would **only** include the values that were **sent by the client**.
|
||||
|
||||
@ -112,7 +112,7 @@ So, if the client sent a JSON with no values:
|
||||
{}
|
||||
```
|
||||
|
||||
Then the dictionary we would get in Python using `hero.dict(exclude_unset=True)` would be:
|
||||
Then the dictionary we would get in Python using `hero.model_dump(exclude_unset=True)` would be:
|
||||
|
||||
```Python
|
||||
{}
|
||||
@ -126,7 +126,7 @@ But if the client sent a JSON with:
|
||||
}
|
||||
```
|
||||
|
||||
Then the dictionary we would get in Python using `hero.dict(exclude_unset=True)` would be:
|
||||
Then the dictionary we would get in Python using `hero.model_dump(exclude_unset=True)` would be:
|
||||
|
||||
```Python
|
||||
{
|
||||
@ -152,6 +152,9 @@ Then we use that to get the data that was actually sent by the client:
|
||||
|
||||
///
|
||||
|
||||
/// tip
|
||||
Before SQLModel 0.0.14, the method was called `hero.dict(exclude_unset=True)`, but it was renamed to `hero.model_dump(exclude_unset=True)` to be consistent with Pydantic v2.
|
||||
|
||||
## Update the Hero in the Database
|
||||
|
||||
Now that we have a **dictionary with the data sent by the client**, we can iterate for each one of the keys and the values, and then we set them in the database hero model `db_hero` using `setattr()`.
|
||||
@ -208,7 +211,7 @@ So, if the client wanted to intentionally remove the `age` of a hero, they could
|
||||
}
|
||||
```
|
||||
|
||||
And when getting the data with `hero.dict(exclude_unset=True)`, we would get:
|
||||
And when getting the data with `hero.model_dump(exclude_unset=True)`, we would get:
|
||||
|
||||
```Python
|
||||
{
|
||||
@ -226,4 +229,4 @@ These are some of the advantages of Pydantic, that we can use with SQLModel.
|
||||
|
||||
## Recap
|
||||
|
||||
Using `.dict(exclude_unset=True)` in SQLModel models (and Pydantic models) we can easily update data **correctly**, even in the **edge cases**. 😎
|
||||
Using `.model_dump(exclude_unset=True)` in SQLModel models (and Pydantic models) we can easily update data **correctly**, even in the **edge cases**. 😎
|
||||
|
Reference in New Issue
Block a user