View decorator to create the child pydantic models from the root model.
Project description
Pydantic view helper decorator
Installation
pip install pydantic_view
Usage
In [1]: from uuid import UUID, uuid4
...:
...: from pydantic import BaseModel, Field
...: from pydantic_view import view
...:
...:
...: @view("Create", exclude=["id"])
...: @view("Update")
...: @view("Patch", optional=["username", "password", "address"])
...: @view("Out", exclude=["password"])
...: class User(BaseModel):
...: id: int
...: username: str
...: password: str
...: address: str
...:
In [2]: user = User(id=0, username="human", password="iamaman", address="Earth")
...: user.Out()
...:
Out[2]: Out(id=0, username='human', address='Earth')
In [3]: User.Update(id=0, username="human", password="iamasuperman", address="Earth")
...:
Out[3]: Update(id=0, username='human', password='iamasuperman', address='Earth')
In [4]: User.Patch(id=0, address="Mars")
...:
Out[4]: Patch(id=0, username=None, password=None, address='Mars')
FastAPI example
from typing import List
from fastapi import FastAPI
from fastapi.testclient import TestClient
from pydantic import BaseModel, Field
from pydantic_view import view
@view("Out", exclude=["secret"])
@view("Create", exclude=["id"])
@view("Update", exclude=["id"])
@view("UpdateMany")
@view("Patch", exclude=["id"], optional=["name", "secret"])
@view("PatchMany", optional=["name", "secret"])
class Group(BaseModel):
id: int
name: str
secret: str = None
@view("Out", exclude=["password"], recursive=True)
@view("Create", exclude=["id"], optional_ex={"groups": Field(default_factory=lambda: [Group(id=0, name="default")])})
@view("Update", exclude=["id"])
@view("UpdateMany")
@view("Patch", exclude=["id"], optional=["username", "password", "groups"])
@view("PatchMany", optional=["username", "password", "groups"])
class User(BaseModel):
id: int
username: str
password: str
groups: List[Group]
app = FastAPI()
db = {}
@app.get("/users/{user_id}", response_model=User.Out)
async def get(user_id: int) -> User.Out:
return db[user_id]
@app.post("/users", response_model=User.Out)
async def post(user: User.Create) -> User.Out:
user_id = 0 # generate_user_id()
db[0] = User(id=user_id, **user.dict())
return db[0]
@app.put("/users/{user_id}", response_model=User.Out)
async def put(user_id: int, user: User.Update) -> User.Out:
db[user_id] = User(id=user_id, **user.dict())
return db[user_id]
@app.put("/users", response_model=List[User.Out])
async def put_many(users: List[User.UpdateMany]) -> List[User.Out]:
for user in users:
db[user.id] = user
return users
@app.patch("/users/{user_id}", response_model=User.Out)
async def patch(user_id: int, user: User.Patch) -> User.Out:
db[user_id] = User(**{**db[user_id].dict(), **user.dict(exclude_unset=True)})
return db[user_id]
@app.patch("/users", response_model=List[User.Out])
async def patch_many(users: List[User.PatchMany]) -> List[User.Out]:
for user in users:
db[user.id] = User(**{**db[user.id].dict(), **user.dict(exclude_unset=True)})
return [db[user.id] for user in users]
def test_fastapi():
client = TestClient(app)
# POST
response = client.post(
"/users",
json={
"username": "admin",
"password": "admin",
},
)
assert response.status_code == 200
assert response.json() == {
"id": 0,
"username": "admin",
"groups": [{"id": 0, "name": "default"}],
}
# GET
response = client.get("/users/0")
assert response.status_code == 200
assert response.json() == {
"id": 0,
"username": "admin",
"groups": [{"id": 0, "name": "default"}],
}
# PUT
response = client.put(
"/users/0",
json={
"username": "superadmin",
"password": "superadmin",
"groups": [],
},
)
assert response.status_code == 200
assert response.json() == {
"id": 0,
"username": "superadmin",
"groups": [],
}
# PUT many
response = client.put(
"/users",
json=[
{
"id": 0,
"username": "admin",
"password": "admin",
"groups": [{"id": 0, "name": "default", "secret": "secret_value"}],
}
],
)
assert response.status_code == 200
assert response.json() == [
{
"id": 0,
"username": "admin",
"groups": [{"id": 0, "name": "default"}],
}
]
# PATCH
response = client.patch("/users/0", json={"id": 0, "username": "guest"})
assert response.status_code == 200
assert response.json() == {
"id": 0,
"username": "guest",
"groups": [{"id": 0, "name": "default"}],
}
# PATCH many
response = client.patch("/users", json=[{"id": 0, "groups": []}])
assert response.status_code == 200
assert response.json() == [
{
"id": 0,
"username": "guest",
"groups": [],
}
]
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
pydantic_view-0.1.1.tar.gz
(3.9 kB
view details)
Built Distribution
File details
Details for the file pydantic_view-0.1.1.tar.gz
.
File metadata
- Download URL: pydantic_view-0.1.1.tar.gz
- Upload date:
- Size: 3.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.4.2 CPython/3.11.2 Linux/4.15.0-209-generic
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 9173f30d46a4c25a6c80a530fc9519e71d41be68797b13d5618367aacd0846ac |
|
MD5 | 16039ae93756cc3da351722e15d4d010 |
|
BLAKE2b-256 | 5a77d53e2e6e532a7908a940eda4122d475d41bb54a7b12ec0379d6b3a27a022 |
File details
Details for the file pydantic_view-0.1.1-py3-none-any.whl
.
File metadata
- Download URL: pydantic_view-0.1.1-py3-none-any.whl
- Upload date:
- Size: 4.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.4.2 CPython/3.11.2 Linux/4.15.0-209-generic
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 4750ff6614d90e2080ea65f2ec683afc58ea47da67c2f624844fccb0f91759b8 |
|
MD5 | bff995543bb9a8048652c460b0f428da |
|
BLAKE2b-256 | 9bfefe25811712bc44a82d6172b07a42982e6405af476f0096085c74e1fd1d53 |