You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel三张表ORM关联:Project模型获取Category名称

三张表的ORM关联实现(附Project获取Category名称的方法)

我来帮你搞定这个关联问题!首先明确三张表的关系:Project和Expense是一对多,ExpenseCategory和Expense也是一对多,Project要通过中间的Expense表间接关联到ExpenseCategory。下面我分别用Django ORM和SQLAlchemy这两个主流框架来演示:


Django ORM 方案

1. 模型定义

先把三个模型写出来,注意外键和反向关联的设置:

from django.db import models

class ExpenseCategory(models.Model):
    cat_id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=100, verbose_name="分类名称")

    def __str__(self):
        return self.name  # 方便在admin或打印时直接显示名称

class Project(models.Model):
    pro_id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=100, verbose_name="项目名称")

    # 自定义方法,获取该项目关联的所有分类名称
    def get_associated_category_names(self):
        # 通过Expense反向关联过滤,distinct()避免同一个分类重复出现
        return ExpenseCategory.objects.filter(
            expense__project=self
        ).distinct().values_list('name', flat=True)

class Expense(models.Model):
    # 关联Project,related_name方便从Project直接访问Expense集合
    project = models.ForeignKey(Project, on_delete=models.CASCADE, related_name="expenses")
    # 关联ExpenseCategory,同样设置related_name
    category = models.ForeignKey(ExpenseCategory, on_delete=models.CASCADE, related_name="expenses")
    amount = models.DecimalField(max_digits=10, decimal_places=2)
    expense_date = models.DateField()

2. 使用方法

当你拿到一个Project实例时,直接调用自定义方法就能拿到分类名称:

# 假设你要获取pro_id=1的项目的分类
my_project = Project.objects.get(pro_id=1)
category_names = my_project.get_associated_category_names()
# 输出结果类似:['差旅费', '办公用品', '设备采购']

SQLAlchemy ORM 方案

如果用的是SQLAlchemy,模型和关联逻辑如下:

1. 模型定义

from sqlalchemy import Column, Integer, String, Decimal, Date, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, sessionmaker

Base = declarative_base()

class ExpenseCategory(Base):
    __tablename__ = 'expense_category'
    cat_id = Column(Integer, primary_key=True)
    name = Column(String(100), nullable=False)

    # 反向关联Expense
    expenses = relationship("Expense", back_populates="category")

class Project(Base):
    __tablename__ = 'project'
    pro_id = Column(Integer, primary_key=True)
    name = Column(String(100), nullable=False)

    # 反向关联Expense
    expenses = relationship("Expense", back_populates="project")

    # 自定义方法获取分类名称,需要传入session
    def get_associated_category_names(self, session):
        category_query = session.query(ExpenseCategory.name)\
            .join(Expense)\
            .filter(Expense.project == self)\
            .distinct()
        # 把查询结果转成列表
        return [name[0] for name in category_query.all()]

class Expense(Base):
    __tablename__ = 'expense'
    id = Column(Integer, primary_key=True)
    project_id = Column(Integer, ForeignKey('project.pro_id'))
    category_id = Column(Integer, ForeignKey('expense_category.cat_id'))
    amount = Column(Decimal(10, 2))
    expense_date = Column(Date)

    # 正向关联Project和ExpenseCategory
    project = relationship("Project", back_populates="expenses")
    category = relationship("ExpenseCategory", back_populates="expenses")

2. 使用方法

# 假设你已经创建了数据库session
my_project = session.query(Project).filter_by(pro_id=1).first()
category_names = my_project.get_associated_category_names(session)

额外说明

如果你的业务场景是一个项目可以直接关联多个分类(不需要通过Expense),那可以考虑给Project和ExpenseCategory建立多对多关系,但根据你描述的“Expense表包含两个外键关联Project和Expense_Category”,显然是通过费用记录间接关联的场景,上面的方案完全匹配你的需求。

内容的提问来源于stack exchange,提问作者Shakib Zaman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 13:17:38