快速API
将 ormar 与 fastapi 结合使用非常简单。
除了在启动时连接到数据库之外,您需要做的所有其他事情就是用 ormar 模型替换 pydantic 模型。
在这里您可以找到一个非常简单的示例应用程序代码。
!!!警告此示例假设您已经创建了一个数据库。如果不是这种情况,请访问数据库初始化部分。
!!!tip 以下示例(所有部分)应放在一个文件中。
| It's divided into subsections for clarity.
|
!!!note 如果您想了解有关如何在 fastapi 请求和响应中使用 ormar 模型的更多信息,请查看响应和请求文档。
快速入门
!!!note 请注意,您可以在 github 存储库的示例下找到完整的快速启动脚本。
导入和初始化
使用 FastAPI 生命周期定义启动和关闭程序,并在应用程序中使用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 | from typing import List, Optional
import databases
import sqlalchemy
from fastapi import FastAPI
import ormar
from contextlib import asynccontextmanager
from fastapi import FastAPI
@asynccontextmanager
async def lifespan(_: FastAPI) -> AsyncIterator[None]:
if not config.database.is_connected:
await config.database.connect()
yield
if config.database.is_connected:
await config.database.disconnect()
base_ormar_config = ormar.OrmarConfig(
metadata=sqlalchemy.MetaData(),
database=databases.Database("sqlite:///test.db"),
)
app = FastAPI(lifespan=lifespan(base_ormar_config))
|
型号定义
使用适当的字段定义 ormar 模型。
将使用这些模型来代替 pydantic 模型。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 | base_ormar_config = OrmarConfig(
metadata = metadata
database = database
)
class Category(ormar.Model):
ormar_config = base_ormar_config.copy(tablename="categories")
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
class Item(ormar.Model):
ormar_config = base_ormar_config.copy()
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
category: Optional[Category] = ormar.ForeignKey(Category, nullable=True)
|
!!!提示您可以在模型部分阅读有关定义模型的更多信息。
Fastapi端点定义
定义您所需的端点,注意 ormar 模型如何用作response_model 和请求参数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 | @app.get("/items/", response_model=List[Item])
async def get_items():
items = await Item.objects.select_related("category").all()
return items
@app.post("/items/", response_model=Item)
async def create_item(item: Item):
await item.save()
return item
@app.post("/categories/", response_model=Category)
async def create_category(category: Category):
await category.save()
return category
@app.put("/items/{item_id}")
async def get_item(item_id: int, item: Item):
item_db = await Item.objects.get(pk=item_id)
return await item_db.update(**item.model_dump())
@app.delete("/items/{item_id}")
async def delete_item(item_id: int, item: Item = None):
if item:
return {"deleted_rows": await item.delete()}
item_db = await Item.objects.get(pk=item_id)
return {"deleted_rows": await item_db.delete()}
|
!!!note 请注意,在 fastapi 为您初始化后,像 save() 这样的 ormar 模型方法如何直接可用。
!!!note 请注意,您可以直接返回一个模型(或模型列表) - fastapi 将为您将其 jsonize
测试应用程序
运行fastapi
如果你想运行这个脚本并使用 fastapi swagger 首先安装 uvicorn
pip 安装 uvicorn
并启动 fastapi。
uvicorn <filename_without_extension>:app --reload
现在您可以导航到浏览器(默认情况下 fastapi 地址为 127.0.0.1:8000/docs)并使用 api。
!!!info 您可以在 fastapi 文档中阅读有关运行 fastapi 的更多信息。
使用 pytest 进行测试
这里有一个示例测试,将证明一切都按预期工作。
请务必先创建表。如果您使用 pytest,则可以使用固定装置。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 | @pytest.fixture(autouse=True, scope="module")
def create_test_database():
engine = sqlalchemy.create_engine(DATABASE_URL)
metadata.create_all(engine)
yield
metadata.drop_all(engine)
# here is a sample test to check the working of the ormar with fastapi
from starlette.testclient import TestClient
def test_all_endpoints():
# note that TestClient is only sync, don't use asyns here
client = TestClient(app)
# note that you need to connect to database manually
# or use client as contextmanager during tests
with client as client:
response = client.post("/categories/", json={"name": "test cat"})
category = response.json()
response = client.post(
"/items/", json={"name": "test", "id": 1, "category": category}
)
item = Item(**response.json())
assert item.pk is not None
response = client.get("/items/")
items = [Item(**item) for item in response.json()]
assert items[0] == item
item.name = "New name"
response = client.put(f"/items/{item.pk}", json=item.model_dump())
assert response.json() == item.model_dump()
response = client.get("/items/")
items = [Item(**item) for item in response.json()]
assert items[0].name == "New name"
response = client.delete(f"/items/{item.pk}", json=item.model_dump())
assert response.json().get("deleted_rows", "__UNDEFINED__") != "__UNDEFINED__"
response = client.get("/items/")
items = response.json()
assert len(items) == 0
|
!!!提示如果您想查看更多测试用例以及如何测试 ormar/fastapi,请参阅 github 存储库中的测试目录
!!!info 您可以在 fastapi 文档中阅读有关测试 fastapi 的更多信息。