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

如何使用Peewee Python ORM对交叉连接子查询进行预取?

使用Peewee实现交叉连接子查询的预取操作

首先我先补全你未写完的Actual模型(假设结构和Plan类似,用于存储实际销量数据),然后分两种常用场景来实现你的需求:

import peewee

class BaseModel(peewee.Model):
    class Meta:
        database = peewee.SqliteDatabase(':memory:')  # 替换为你的实际数据库配置

class Product(BaseModel):
    product_id = peewee.CharField(primary_key=True)
    list_price = peewee.FloatField()

class Week(BaseModel):
    week_date = peewee.DateField(primary_key=True)

class Plan(BaseModel):
    product = peewee.ForeignKeyField(Product, backref='plans')
    week = peewee.ForeignKeyField(Week, backref='plans')
    sales = peewee.FloatField(null=True)
    class Meta:
        primary_key = peewee.CompositeKey('product', 'week')

class Actual(BaseModel):
    product = peewee.ForeignKeyField(Product, backref='actuals')
    week = peewee.ForeignKeyField(Week, backref='actuals')
    actual_sales = peewee.FloatField(null=True)
    class Meta:
        primary_key = peewee.CompositeKey('product', 'week')

# 初始化表(仅首次运行需要)
BaseModel.create_tables([Product, Week, Plan, Actual])

方案1:SQL层面直接实现交叉连接+左关联(大数据量推荐)

这种方式通过一次SQL查询完成笛卡尔积生成和关联数据匹配,效率更高,适合数据量较大的场景:

# 构建交叉连接(Product × Week)+左关联Plan和Actual的查询
query = (Product
         .select(
             Product.product_id,
             Week.week_date,
             Plan.sales.alias('plan_sales'),
             Actual.actual_sales.alias('actual_sales')
         )
         .join(Week, on=None)  # on=None 触发SQL的CROSS JOIN
         .join(Plan, on=(
             (Product.product_id == Plan.product) & (Week.week_date == Plan.week)
         ), join_type=peewee.JOIN.LEFT_OUTER)
         .join(Actual, on=(
             (Product.product_id == Actual.product) & (Week.week_date == Actual.week)
         ), join_type=peewee.JOIN.LEFT_OUTER))

# 遍历查询结果
for row in query.tuples():
    product_id, week_date, plan_sales, actual_sales = row
    print(f"Product: {product_id}, Week: {week_date}")
    print(f"  计划销量: {plan_sales if plan_sales else '无数据'}")
    print(f"  实际销量: {actual_sales if actual_sales else '无数据'}")

方案2:内存中生成交叉组合并匹配关联数据(小数据量推荐)

如果数据量不大,这种方式代码更直观,不需要复杂的SQL拼接:

# 先批量加载所有基础数据到内存
products = {p.product_id: p for p in Product.select()}
weeks = {w.week_date: w for w in Week.select()}
plans = {(p.product_id, p.week.week_date): p for p in Plan.select()}
actuals = {(a.product_id, a.week.week_date): a for a in Actual.select()}

# 生成所有Product×Week的交叉组合,并匹配对应的Plan和Actual
class ProductWeekCombo:
    def __init__(self, product, week, plan=None, actual=None):
        self.product = product
        self.week = week
        self.plan = plan
        self.actual = actual

combinations = []
for product in products.values():
    for week in weeks.values():
        key = (product.product_id, week.week_date)
        combinations.append(ProductWeekCombo(
            product=product,
            week=week,
            plan=plans.get(key),
            actual=actuals.get(key)
        ))

# 遍历组合数据
for combo in combinations:
    print(f"Product: {combo.product.product_id}, Week: {combo.week.week_date}")
    print(f"  计划销量: {combo.plan.sales if combo.plan else '无数据'}")
    print(f"  实际销量: {combo.actual.actual_sales if combo.actual else '无数据'}")

注意事项

Peewee默认的prefetch方法是基于外键的关联查询,适合常规的一对多/多对多场景,但交叉连接属于笛卡尔积,没有直接的外键关联关系,因此需要通过上述两种方式实现需求。

内容的提问来源于stack exchange,提问作者Mike Drawback

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:35:05