微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Fastapi/Tortoise 早期模型初始化

如何解决Fastapi/Tortoise 早期模型初始化

我使用 fastapi 实现了以下实现。

我目前的问题是,我终生无法在乌龟模型上执行 early init 以将关系恢复到模式中。

我试过基本上到处都转储以下行,但它似乎不起作用。

Tortoise.init_models(["models.user","models.group"],"models")

我也试过以这种方式使用 prefetch_related 但这也不起作用

GetGroup.from_queryset(Group.get(id=3).prefetch_related('owner'))

我已经在谷歌上搜索了几个小时,但没有找到一个具体的答案/方法来让它正常工作。

文件夹结构:

app
│   main.py
└───database
│   │   database.py
└───models
|    │   user.py
|    │   group.py
└───routers
|   │   user_router.py
|   │   group_router.py
└───services
|   │   auth.py
文件
from fastapi import FastAPI
from database.database import init_db
from routers.user_router import router as UserRouter
from routers.group_router import router as GroupRouter

# Instantiate the Application
app = FastAPI(title="test",root_path="/api/")

# Include the Routers
app.include_router(UserRouter,tags=["User"],prefix="/user")
app.include_router(GroupRouter,tags=["Group"],prefix="/group")


# Start DB Connection on Startup
@app.on_event("startup")
async def startup_event():
    init_db(app)
数据库/数据库.py
from decouple import config
from fastapi import FastAPI
from tortoise import Tortoise
from tortoise.contrib.fastapi import register_tortoise


def init_db(app: FastAPI) -> None:
    Tortoise.init_models(["models.user","models")
    register_tortoise(
        app,db_url=f"MysqL://{config('MysqL_USER')}:{config('MysqL_PASSWORD')}@{config('MysqL_HOST')}:{config('MysqL_EXPOSE')}/{config('MysqL_DB')}",modules={"models": ["models.user","models.group",]},generate_schemas=False,add_exception_handlers=True,)


TORTOISE_ORM = {
    "connections": {"default": f"MysqL://{config('MysqL_USER')}:{config('MysqL_PASSWORD')}@{config('MysqL_HOST')}:{config('MysqL_EXPOSE')}/{config('MysqL_DB')}"},"apps": {
        "models": {
            "models": ["models.user","aerich.models"],"default_connection": "default",},}
模型/用户.py
from tortoise import fields
from tortoise.models import Model
from tortoise.contrib.pydantic import pydantic_model_creator
from models.group import Group


class User(Model):
    # ##### Define Readonly Fields ##### #
    id = fields.BigIntField(pk=True)
    # ##### Define normal Fields ##### #
    first_name = fields.CharField(max_length=50)
    last_name = fields.CharField(max_length=50)
    username = fields.CharField(max_length=50,unique=True)
    email = fields.CharField(max_length=50,unique=True)
    password = fields.CharField(max_length=128)
    # ##### Define O2M ##### #
    owned_groups: fields.ReverseRelation[Group]
    # ##### Define M2M ##### #
    groups: fields.ManyToManyRelation[Group]
    # ##### Define Time_Stamps ###### #
    created_at = fields.DatetimeField(auto_Now_add=True)
    modified_at = fields.DatetimeField(auto_Now=True)

    class Meta:
        table: str = 'users'


AuthData = pydantic_model_creator(User)
createuser = pydantic_model_creator(User,name="createuser",exclude_readonly=True)
UpdateUser = pydantic_model_creator(User,name="UpdateUser",exclude_readonly=True,exclude=['password'])
GetUser = pydantic_model_creator(User,name="GetUser",exclude=['password'])
ChangeUserPassword = pydantic_model_creator(User,name="ChangeUserPassword",include=['password'])
模型/组.py
from tortoise import fields
from tortoise.models import Model
from tortoise.contrib.pydantic import pydantic_model_creator


class Group(Model):
    # ##### Define Readonly Fields ##### #
    id = fields.BigIntField(pk=True)
    # ##### Define normal Fields ##### #
    name = fields.CharField(max_length=50,unique=True)
    # ##### Define O2M ##### #
    owner = fields.ForeignKeyField("models.User",related_name="owned_groups")
    # ##### Define M2M ##### #
    members = fields.ManyToManyField("models.User",related_name="groups")
    # ##### Define Time_Stamps ###### #
    created_at = fields.DatetimeField(auto_Now_add=True)
    modified_at = fields.DatetimeField(auto_Now=True)

    class Meta:
        table: str = 'groups'


CreateGroup = pydantic_model_creator(Group,name="CreateGroup",exclude=['members'])
UpdateGroup = pydantic_model_creator(Group,name="UpdateGroup",exclude=['members'])
GetGroup = pydantic_model_creator(Group,name="GetGroup")
路由器/group_router.py
from typing import List
import json
from fastapi import HTTPException,APIRouter,Depends,status
from models.user import User
from models.group import Group,CreateGroup,UpdateGroup,GetGroup
from tortoise.contrib.fastapi import HTTPNotFoundError
from services.auth import current_user

# Intialize Router
router = APIRouter()


# ###################### Define Routes ###################### #

# Create A Group
@router.post("/",dependencies=[Depends(current_user)])
async def create_group(group: CreateGroup,user: User = Depends(current_user)):
    user = await user
    try:
        await Group.create(**group.dict(exclude_unset=True),owner_id=user.id)
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,detail="Group Name Already Exists"
        )
    return {"Group Created Successfully"}


# Update A Group
@router.put("/{group_id}",dependencies=[Depends(current_user)],responses={404: {"model": HTTPNotFoundError}})
async def update_group(group_id: int,group: UpdateGroup,user: User = Depends(current_user)):
    user = await user
    group = await GetGroup.from_queryset_single(Group.get(id=group_id))
    return group
    if user.id == group.id:
        await Group.filter(id=group_id).update(**group.dict(exclude_unset=True))
        return {"Group Successfully Updated"}
    else:
        raise HTTPException(
            status_code=status.HTTP_406_NOT_ACCEPTABLE,detail="You can't edit a group unless you're the owner"
        )


# Get All Groups
@router.get("/",dependencies=[Depends(current_user)])
async def get_groups():
    return GetGroup.schema()

如您所见,最后一行 GetGroup.schema() 永远不会返回关系。

我尝试在容器启动时捕获日志并得到以下结果

[2021-04-24 19:59:53 +0000] [1255] [INFO] Started server process [1255]
[2021-04-24 19:59:53 +0000] [1255] [INFO] Waiting for application startup.
[2021-04-24 19:59:53 +0000] [1255] [ERROR] Traceback (most recent call last):
File "/usr/local/lib/python3.8/site-packages/tortoise/__init__.py",line 358,in _discover_models
module = importlib.import_module(models_path)
File "/usr/local/lib/python3.8/importlib/__init__.py",line 127,in import_module
return _bootstrap._gcd_import(name[level:],package,level)
File "<frozen importlib._bootstrap>",line 1014,in _gcd_import
File "<frozen importlib._bootstrap>",line 991,in _find_and_load
File "<frozen importlib._bootstrap>",line 973,in _find_and_load_unlocked
ModuleNotFoundError: No module named 'a'
During handling of the above exception,another exception occurred:
Traceback (most recent call last):
File "/usr/local/lib/python3.8/site-packages/starlette/routing.py",line 526,in lifespan
async for item in self.lifespan_context(app):
File "/usr/local/lib/python3.8/site-packages/starlette/routing.py",line 467,in default_lifespan
await self.startup()
File "/usr/local/lib/python3.8/site-packages/starlette/routing.py",line 502,in startup
await handler()
File "/app/main.py",line 17,in startup_event
init_db(app)
File "/app/database/database.py",line 8,in init_db
Tortoise.init_models("app.models.user","models")
File "/usr/local/lib/python3.8/site-packages/tortoise/__init__.py",line 415,in init_models
app_models += cls._discover_models(models_path,app_label)
File "/usr/local/lib/python3.8/site-packages/tortoise/__init__.py",line 360,in _discover_models
raise ConfigurationError(f'Module "{models_path}" not found')
tortoise.exceptions.ConfigurationError: Module "a" not found
[2021-04-24 19:59:53 +0000] [1255] [ERROR] Application startup Failed. Exiting.

请注意,它会这样做几秒钟,然后应用程序正确启动, 我还尝试在名为“schema”的单独文件夹中分离 pydantic 模型创建,但也没有做任何事情

解决方法

所以我终于找到了答案,我会把它留在这里,以防有些可怜的人偶然发现这个问题

诀窍是移动

from database.database import init_db

main.py 文件的顶部

并添加

Tortoise.init_models(["models.user","models.group"],"models")

在 init_db() 函数下方,以便在 register_tortoise 函数执行和所有模型初始化之前调用它

信息来源:https://stackoverflow.com/a/65881146/13637905

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。