Replace custom field validators with Extra.forbid by @anton-shum

This commit is contained in:
Anton Shum
2022-09-16 20:12:26 +02:00
committed by GitHub
parent cab4b1ab1a
commit d17d0fecf9

View File

@@ -664,28 +664,17 @@ print(type(post.content))
# OUTPUT: Article # OUTPUT: Article
# Article is very inclusive and all fields are optional, allowing any dict to become valid # Article is very inclusive and all fields are optional, allowing any dict to become valid
``` ```
**Not Terrible Solutions:** **Solutions:**
1. Order field types properly: from the most strict ones to loose ones. 1. Validate input has only valid fields
```python ```python
class Post(BaseModel): from pydantic import BaseModel, Extra, root_validator
content: Video | Article
```
2. Validate input has only valid fields
```python
from pydantic import BaseModel, root_validator
class Article(BaseModel): class Article(BaseModel):
text: str | None text: str | None
extra: str | None extra: str | None
@root_validator(pre=True) # validate all values before pydantic class Config:
def has_only_article_fields(cls, data: dict): extra = Extra.forbid
"""Silly and ugly solution to validate data has only article fields."""
fields = set(data.keys())
if fields != {"text", "extra"}:
raise ValueError("invalid fields")
return data
class Video(BaseModel): class Video(BaseModel):
@@ -693,20 +682,14 @@ class Video(BaseModel):
text: str | None text: str | None
extra: str | None extra: str | None
@root_validator(pre=True) class Config:
def has_only_video_fields(cls, data: dict): extra = Extra.forbid
"""Silly and ugly solution to validate data has only video fields."""
fields = set(data.keys())
if fields != {"text", "extra", "video_id"}:
raise ValueError("invalid fields")
return data
class Post(BaseModel): class Post(BaseModel):
content: Article | Video content: Article | Video
``` ```
3. Use Pydantic's Smart Union (>v1.9) if fields are simple 2. Use Pydantic's Smart Union (>v1.9) if fields are simple
It's a good solution if the fields are simple like `int` or `bool`, It's a good solution if the fields are simple like `int` or `bool`,
but it doesn't work for complex fields like classes. but it doesn't work for complex fields like classes.
@@ -748,6 +731,16 @@ print(type(p.field_2))
print(type(p.content)) print(type(p.content))
# OUTPUT: Article, because smart_union doesn't work for complex fields like classes # OUTPUT: Article, because smart_union doesn't work for complex fields like classes
``` ```
**Fast Workaround:**
Order field types properly: from the most strict ones to loose ones.
```python
class Post(BaseModel):
content: Video | Article
```
### 19. SQL-first, Pydantic-second ### 19. SQL-first, Pydantic-second
- Usually, database handles data processing much faster and cleaner than CPython will ever do. - Usually, database handles data processing much faster and cleaner than CPython will ever do.
- It's preferable to do all the complex joins and simple data manipulations with SQL. - It's preferable to do all the complex joins and simple data manipulations with SQL.