使用Peewee Python ORM预取交叉连接子查询

时间:2018-04-09 23:01:17

标签: python sql orm peewee prefetch

我的模特是:

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')
    sales = peewee.FloatField(null=True)
    price = peewee.FloatField(null=True)

    class Meta:
        primary_key = peewee.CompositeKey('product', 'week')

class Forecast(BaseModel):
    product = peewee.ForeignKeyField(Product, backref='forecasts')
    week = peewee.ForeignKeyField(Week, backref='forecasts')
    sales = peewee.FloatField(null=True)

    class Meta:
        primary_key = peewee.CompositeKey('product', 'week')

我以Plan类为基础进行查询,从“产品”和“周”中选择以获取所有可能的组合,并使用任何现有的实际值,计划和预测进行注释。

query = Plan.select(
    Product.product_id,
    Week.week_date,
    Plan.sales.alias('plan_sales'),
    Actual.sales.alias('actual_sales'),
    Forecast.sales.alias('forecast_sales')
    ).from_(Product, Week
    ).join(Plan, "LEFT OUTER", 
        on=((Plan.week==Week.week_date)&
        (Plan.product==Product.product_id))
    ).join(Forecast, "LEFT OUTER", 
        on=((Forecast.week==Week.week_date)& 
        (Forecast.product==Product.product_id))
    ).join(Actual, "LEFT OUTER",
        on=((Actual.week==Week.week_date)& 
        (Actual.product==Product.product_id))
    )

这就是我想要的。无论计划,实际或预测是否存在,我都会获得所有可能产品和周的计划对象。

但是,当我尝试从Product或Week预取此查询时,交叉连接会丢失。

>>> query.where(Week.week_date=='2018-04-29').objects().count()
17

>>> weeks_with_plans = Week.select().prefetch(query.objects())
>>> weeks_with_plans[0]
<Week: '2018-04-29'>

>>> weeks_with_plans[0].plans
[<Plan: 'Pr01 2018-04-29'>, <Plan: 'Pr02 2018-04-29'>]

交叉连接查询返回2018-04-29周的所有17个可能的计划对象,但是当我在同一周查询预取时,只有2个对象被附加到同一周实例。

Peewee的prefetch_add_subquery()正在添加到原始查询的WHERE子句中:

AND ("plan"."week_id" IN (SELECT "week"."week_date" FROM "week"))

这将预取限制为计划表中实际存在的产品/周组合,从而消除了交叉连接的影响。我如何预取给定的周或产品的交叉组合,就像我从原始子查询中得到的那样?

0 个答案:

没有答案