搜索功能前后端代码解析

搜索功能具体实现代码

# 导入必要的模块和函数  
from fastapi import APIRouter, HTTPException  # 导入FastAPI的APIRouter和HTTPException  
from app.db.models import MbBill, MbCategory, MbAsset  # 导入数据库模型  
from pydantic import BaseModel, Field  # 导入Pydantic的BaseModel和Field  
from tortoise.contrib.pydantic import pydantic_model_creator, pydantic_queryset_creator  # 导入Tortoise ORM的Pydantic集成工具  
from tortoise.functions import Trim, Sum, Count  # 导入Tortoise ORM的SQL函数(尽管此处未使用Trim, Sum, Count)  
from typing import Union, Optional  # 导入类型注解(此处仅使用了Union和Optional的导入,但代码中未直接使用)  
from decimal import Decimal  # 导入Decimal类型(代码中未直接使用)  
from utility import func  # 导入自定义的工具模块  
from .items import MonthPagerItem  # 导入自定义的MonthPagerItem类(但在此代码中未使用)  
  
# 定义路由的名称  
name = "统计"  
  
# 创建APIRouter实例,设置前缀和标签  
router = APIRouter(  
    prefix="/stat",  
    tags=[name],  
    responses={404: {"description": "Not found"}},  
)  
  
# 定义一个类(尽管在后续代码中未被实例化或使用)  
class MonthItem():  
    month: datetime  # 注意:这里缺少了datetime的导入,应添加from datetime import datetime  
  
# 定义一个响应模板(但模板中的字段在函数内部未被直接使用)  
RES = {  
    "code": 0,  
    "result": {  
        "expend": 10000,  
        "income": 20000,  
        "expendAvg": 15000,  
    }  
}  
  
# 获取搜索分组分页账单的路由处理函数  
@router.get("/pages/search/{keyword}", summary=name, description=name, responses=func.Responses(name, RES))  
async def stat_pages(keyword: str):  
    # 创建一个Pydantic模型,用于从MbBill模型中排除一些字段  
    bills = pydantic_model_creator(MbBill, exclude=(  
        "isDel", "created", "modified", "category.created", "category.modified", "category.isDel", "category.sort",  
        "asset.created", "asset.modified", "asset.isDel", "asset.sort"))  
      
    # 从数据库中查询未删除且描述中包含关键词的账单,并按时间降序排序  
    res = await MbBill.filter(isDel=0, description__contains=keyword).order_by('-time')  
      
    # 初始化一个集合来存储查询结果的唯一日期  
    days = set()  
    for r in res:  
        days.add(r.time.date())  
      
    # 初始化响应列表,按日期分组  
    RES = []  # 注意:这里重用了RES变量,可能会与之前的响应模板混淆  
    Days = list(days)  
    Days.sort()  # 对日期进行升序排序(但这里排序后并未直接用于控制显示顺序)  
    for d in Days:  
        RES.append({'date': d, 'items': []})  
      
    # 遍历查询结果,将账单按日期分组  
    for r in res:  
        for d in RES:  
            if r.time.date() == d['date']:  
                # 注意:这里对每个账单都执行了额外的数据库查询,性能不佳  
                r2 = await bills.from_tortoise_orm(await MbBill.get(id=r.id))  
                d['items'].append(r2)  
      
    # 返回响应,包含查询总数(应为len(res))和按日期分组的账单列表  
    return {  
        "code": 0,  
        "result": {  
            "total": len(res),  # 添加查询总数  
            "items": RES  
        }  
    }

其中实现筛选功能的代码段是res = await MbBill.filter(isDel=0, description__contains=keyword).order_by('-time')

这行代码的含义是:

  • isDel=0:筛选出isDel字段等于0的记录,即未删除的账单记录。
  • description__contains=keyword:筛选出description字段中包含keyword(即函数参数中传入的搜索关键词)的记录。

然后,通过.order_by('-time')对这些筛选后的记录按照time字段进行降序排序。

因此,筛选标准主要是基于账单的删除状态(isDel)和描述(description)字段来进行的。如果账单记录未被删除(isDel=0)且其描述中包含指定的关键词(keyword),那么这些记录就会被选出来并进行后续的排序和分组处理。

如何增加筛选标准

在Tortoise ORM中,你可以通过filter()方法链式地添加多个筛选条件。如果你想要在你的stat_pages函数中增添筛选标准,你可以直接在filter()方法中继续添加条件。

例如,如果你想要基于账单的类别(category)或资产(asset)来进一步筛选账单,你可以这样做(假设categoryassetMbBill模型中的外键字段,并且你已经有了它们对应的ID或名称等筛选条件):

示例# 假设你有了额外的筛选条件,比如category_id和asset_id  
category_id = 1  # 示例,实际使用时可以是函数参数或其他逻辑获取  
asset_id = 2     # 示例,实际使用时可以是函数参数或其他逻辑获取  
  
# 增添筛选标准  
res = await MbBill.filter(  
    isDel=0,   
    description__contains=keyword,  
    category_id=category_id,  # 新增的筛选条件  
    asset_id=asset_id         # 新增的筛选条件  
).order_by('-time')

然而,需要注意的是,如果你的MbBill模型中categoryasset是以外键形式存在的,并且你想要通过它们的相关字段(比如名称而不是ID)来筛选,那么你可能需要使用到__操作符来访问关联模型的字段,但这通常涉及到更复杂的查询,并且可能需要使用annotate()prefetch_related()等方法来预先加载关联数据。

由此可见如若想扩大可搜索范围数据库模型很重要

数据库模型解析

# 引入Tortoise ORM的基础模型和字段  
from tortoise.models import Model  
from tortoise import fields  
from tortoise.fields import IntField, CharField, DateField, FloatField, DatetimeField, DecimalField  
  
# 定义一个基础模型类,包含通用字段  
class BaseModel(Model):  
    # 添加数据时间,自动设置为记录创建时间  
    created = fields.DatetimeField(null=True, auto_now_add=True)  
    # 修改数据时间,自动更新为每次记录修改的时间  
    modified = fields.DatetimeField(null=True, auto_now=True)  
    # 逻辑删除标记,0表示未删除,非0表示已删除  
    isDel = IntField(default=0)  
    # 微信ID或所有者标识,为空时表示公用  
    userid = CharField(null=True, max_length=20)  
  
    # 自定义方法,用于执行原始SQL查询并返回结果  
    @classmethod  
    async def get_by_query(cls, query):  
        db = Tortoise.get_connection("default")  
        result = await db.execute_query_dict(query)  
        return result  
  
    class Meta:  
        # 标记为抽象类,不会被Tortoise ORM创建对应的数据库表  
        abstract = True  
  
# 账户表模型  
class MbAsset(BaseModel):  
    # 主键ID  
    id = IntField(pk=True)  
    # 父级ID,用于构建层级关系  
    pid = IntField(default=0)  
    # 账户名称  
    name = CharField(max_length=50)  
    # 类型字段(当前未使用,可按需添加)  
    # type = CharField(max_length=20)  
    # 图标路径  
    iconPath = CharField(max_length=20)  
    # 账户余额  
    amount = FloatField(default=0, null=True)  
    # 排序字段  
    sort = IntField(default=0)  
    # 反向关联到账单表,用于查询该账户下的所有账单  
    bills: fields.ReverseRelation["MbBill"]  
  
    class Meta:  
        # 指定数据库表名  
        table = "asset"  
  
# 账单类别模型  
class MbCategory(BaseModel):  
    # 主键ID  
    id = IntField(pk=True)  
    # 父级ID,用于构建层级关系  
    pid = IntField(default=0)  
    # 类别名称  
    name = CharField(max_length=255)  
    # 类别类型,1表示支出,0表示收入  
    type = IntField(null=True)  
    # 图标路径  
    iconPath = CharField(max_length=20)  
    # 预算金额  
    budget = FloatField(default=0, null=True)  
    # 排序字段  
    sort = IntField(default=0)  
    # 反向关联到账单表,用于查询该类别下的所有账单  
    bills: fields.ReverseRelation["MbBill"]  
  
    class Meta:  
        # 指定数据库表名  
        table = "category"  
  
# 账单模型  
class MbBill(BaseModel):  
    # 主键ID  
    id = IntField(pk=True, description="ID")  
    # 账单类型(根据业务需求定义)  
    type = IntField()  
    # 账单金额,使用DecimalField以精确表示金额  
    amount = DecimalField(max_digits=10, decimal_places=2, null=False, default=0)  
    # 外键关联到账单类别表  
    category: fields.ForeignKeyRelation["MbCategory"] = \  
        fields.ForeignKeyField("models.MbCategory", related_name="bills")  
    # 外键关联到账户表  
    asset: fields.ForeignKeyRelation["MbAsset"] = \  
        fields.ForeignKeyField("models.MbAsset", related_name="bills")  
    # 账单描述  
    description = CharField(max_length=255, null=True)  
    # 账单地址(如购物地点)  
    address = CharField(max_length=255, null=True)  
    # 账单时间,自动设置为记录创建时间  
    time = DatetimeField(null=True, auto_now_add=True)  
  
    class Meta:  
        # 指定数据库表名  
        table = "bill"  
        # 设置默认排序字段  
        ordering = ["created"]  
  
# 预购清单分组实体模型  
class PreOrderGroup(BaseModel):  
    # 主键ID  
    id = IntField(pk=True, description="ID")  
    # 关联的账单ID  
    billId = IntField(default=0)  
    # 分组名  
    name = CharField(max_length=20, null=False)  
    # 分组描述  
    description = CharField(max_length=255, null=True)  
  
# 预购清单项目模型  
class PreOrder(BaseModel):  
    # 主键ID  
    id = IntField(pk=True, description="ID")  
    # 外键关联到预购清单分组实体  
    orderGroup: fields.ForeignKeyRelation["PreOrderGroup"] = \  
        fields.ForeignKeyField("models.PreOrderGroup")  
    # 预算金额  
    preAmount = DecimalField(max_digits=10, decimal_places=2, null=False, default=0)  
    # 实际支付金额  
    realAmount = DecimalField(max_digits=10, decimal_places=2, null=False, default=0)  
    # 时间戳,自动设置为记录创建时间  
    time = DatetimeField(null=True, auto_now_add=True)  
    # 购买状态,0表示未购买,1表示已购买  
    status = IntField(null=False, default=0)  
    # 项目描述  
    description = CharField(max_length=255, null=True)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值