FastAPI+Tortoise ORM+FastAPI用户(Python)-关系-多对多

FastAPI + Tortoise ORM + FastAPI Users (Python) - Relationship - Many To Many(FastAPI+Tortoise ORM+FastAPI用户(Python)-关系-多对多)
本文介绍了FastAPI+Tortoise ORM+FastAPI用户(Python)-关系-多对多的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用FastAPI、Tortoise ORM和FastAPI用户制作一个API来学习。基本上,我从OpenWeather API获取城市天气数据,并使用Tortoise ORM存储在SQLite数据库中。我对FastAPI用户进行了身份验证。

我使用的是外键,关系运行良好。但现在我想要一些改变(一种改进)。我希望每个用户都有他们的项目,并且在登录并访问终结点(@router.get("/me/onlyitems/", response_model=List[schemas.Card_Pydantic]))之后,它只接收他们的项目。

它工作得很好,我只接收用户项(使用Owner_id),但我的项表使用外部唯一ID(项是一个城市,并且每个城市都有一个唯一ID),并且它是主键。 但是,当另一个用户尝试添加相同的城市时,它会给出一个错误,因为表中不能有相同的城市,即使是与另一个所有者。嗯,应该是这样的.但我想让其他用户访问相同的城市(他们有相同的信息,他们不是定制的)。 然后,我希望多个用户能够访问同一项目(每个用户可以访问多个项目)。

我认为为每个用户重复项目信息(使用另一个ID)并不理想,不同的用户访问同一项目会更好。

我认为这将是一个多对多的关系,但我不知道如何建立这种关系并使用FastAPI获得它。

我想过创建一个只有UserID和CityID(以及一个自动递增ID)的中间表,并使用它来获取相关数据,但我不知道这是最好的方法还是可行的。

我尝试向Tortoise文档学习,但我找不到我需要的部分,也无法理解文档中的一些复杂示例和部分内容。

我使用的是包的更新版本和Python3.9.4

好的,让我展示一些代码:

Models.py

class UserModel(TortoiseBaseUserModel):  # From FastAPI Users
    cards: fields.ReverseRelation["Card"]


class OAuthAccountModel(TortoiseBaseOAuthAccountModel): # From FastAPI Users
    user = fields.ForeignKeyField("models.UserModel", related_name="oauth_accounts")


class User(models.BaseUser, models.BaseOAuthAccountMixin): # From FastAPI Users
    pass


class UserCreate(models.BaseUserCreate): # From FastAPI Users
    pass


class UserUpdate(User, models.BaseUserUpdate): # From FastAPI Users
    pass


class UserDB(User, models.BaseUserDB, PydanticModel): # From FastAPI Users
    class Config:
        orm_mode = True
        orig_model = UserModel


user_db = TortoiseUserDatabase(UserDB, UserModel, OAuthAccountModel) # From FastAPI Users


class Card(tmodels.Model):
    """
    The Card model, related to the user.
    """
    id = fields.IntField(pk=True)
    city_name = fields.CharField(max_length=30)
    temperature = fields.FloatField()
    state = fields.CharField(max_length=30, null=True)
    icon = fields.CharField(max_length=3, null=True)
    period = fields.CharField(max_length=20, null=True)
    created_at = fields.DatetimeField(auto_now_add=True)
    updated_at = fields.DatetimeField(auto_now=True)
    owner: fields.ForeignKeyRelation[UserModel] = fields.ForeignKeyField(
        "models.UserModel", related_name="cards")

    class PydanticMeta:
        exclude = ["owner"]

我尝试更改我的所有者字段及其与UserModel的关系:

class Card(tmodels.Model):
owner = fields.ManyToManyField("models.UserModel", related_name="cards")
class UserModel(TortoiseBaseUserModel):
    cards: fields.ManyToManyRelation["Card"]

我不知道它是否正确,我无法使其工作,但问题可能出在其他地方。

我的用户终结点创建项目:

@router.post("/", response_model=Card_Pydantic)
async def create_item_for_current_user(
        card: CardCreate, user: UserDB = Depends(fastapi_users.get_current_active_user)):
    card_obj = await crud.create_user_card(card=card, user=user)
    if card_obj is None:
        raise HTTPException(status_code=404, detail=f"City '{card.city_name}' not found")
    return await card_obj

此处使用的CRUD函数(用于创建项目):

async def create_user_card(
        card: schemas.CardCreate, user: UserDB = Depends(fastapi_users.get_current_active_user)):
    card_json = await weather_api.get_api_info_by_name(card.city_name)
    if card_json is None:
        return None
    card_obj = await Card.create(**card_json,
                                 owner_id=user.id)  # ** is used to pass the keys values as kwargs.
    return await card_obj

我的终结点以获取用户拥有的项目:

@router.get("/me/onlyitems/", response_model=List[schemas.Card_Pydantic])
async def read_current_user_items(user: UserDB = Depends(fastapi_users.get_current_active_user)):
    user_cards = await schemas.Card_Pydantic.from_queryset(Card.filter(owner_id=user.id).all())
    return await crud.update_only_card_for(user_cards, user.id)

我的CRUD函数是:

async def update_only_card_for(user_cards, owner_id):
    for city in user_cards:
        await update_card(city.id, owner_id)
    return await schemas.Card_Pydantic.from_queryset(Card.filter(owner_id=owner_id).all())

# The update function (it will check if it need to update or not)
async def update_card(city_id: int, owner_id: UUID = UserDB):
    card_obj = await Card.get(id=city_id)
    card_time = card_obj.updated_at
    timezone = card_time.tzinfo
    now = datetime.now(timezone)
    time_to_update = now - timedelta(minutes=15)

    if card_time < time_to_update:
        card_json = await weather_api.get_api_info_by_id(city_id)
        await card_obj.update_from_dict(card_json).save()  # with save will update the update_at field
    card_updated = await schemas.Card_Pydantic.from_queryset_single(Card.get(id=city_id))
    return card_updated

如何更改才能获得用户需要访问的卡?我认为我不能使用按Owner_id筛选(好的,如果我可以创建我的中间表,我可以,但不知道如何做和获取数据),但是我不知道如何建立关系来将用户链接到他添加的项目,同时其他用户访问相同的项目。

此代码运行良好(我使用的是nuxt.js前端),直到有重复的城市...

处理它的最佳方式是什么?如何处理?

谢谢,迭戈。

推荐答案

我解决了。我认为Tortoise文档有点令人困惑,但我找到了如何创建关系和检索数据。

模型:(简化版)

class Card(tmodels.Model):
    id = fields.IntField(pk=True)
    city_name = fields.CharField(max_length=30)
    owners: fields.ManyToManyRelation["UserModel"] = fields.ManyToManyField(
        "models.UserModel", related_name="cards", through="card_usermodel")

class UserModel(TortoiseBaseUserModel):
    cards: fields.ManyToManyRelation[Card]

through="card_usermodel"将使用卡ID和所有者ID创建中间表,它将定义关系。

进行数据操作:

async def create_user_card(
        card: schemas.CardCreate, user: UserDB = Depends(fastapi_users.get_current_active_user)):
    card_json = await weather_api.get_api_info_by_name(card.city_name)
    if card_json is None:
        return None
    owner = await UserModel.get_or_none(id=user.id)
    card_obj = await Card.update_or_create(**card_json)
    await card_obj[0].owners.add(owner)
    return await schemas.Card_Response_Pydantic.from_queryset_single(Card.get(id=card_json.get("id"), owners=user.id))

基本就是这样。我还更改了一些平凡的模型,以验证响应。

这篇关于FastAPI+Tortoise ORM+FastAPI用户(Python)-关系-多对多的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

Flask + PyMySQL giving error no attribute #39;settimeout#39;(FlASK+PyMySQL给出错误,没有属性#39;setTimeout#39;)
How should make faster SQL Server filtering procedure with many parameters(如何让多参数的SQL Server过滤程序更快)
Inserting NaN value into MySQL Database(将NaN值插入MySQL数据库)
How to define composite foreign key mapping in hibernate?(如何在Hibernate中定义复合外键映射?)
Window functions not working in pd.read_sql; Its shows error(窗口函数在pd.read_sql中不起作用;它显示错误)
(Closed) Leaflet.js: How I can Do Editing Geometry On Specific Object I Select Only?((已关闭)Leaflet.js:如何仅在我选择的特定对象上编辑几何图形?)