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

如何高效从Django关联表生成目标结构的Pandas DataFrame?

高效生成订单-商品列表Pandas DataFrame的优化方案

问题背景

需要生成用于规则挖掘的Pandas DataFrame,目标结构如下:

orderproducts
1['product1', 'product2']
2['product1', 'product3', 'product10']
......

Django模型定义

class Order(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    product = models.ManyToManyField(Product, through='OrderedProduct', related_name='orders')

class OrderedProduct(models.Model):
    order = models.ForeignKey(Order, on_delete=models.CASCADE)
    product = models.ForeignKey(Product, on_delete=models.DO_NOTHING)
    quantity = models.IntegerField(default=1)

class Product(models.Model):
    name = models.CharField(max_length=255)
    price = models.DecimalField(max_digits=10, decimal_places=2)

现有实现(大数据集下效率偏低)

orders = OrderedProduct.objects.all().values('order__id', 'product__name')
df = pd.DataFrame.from_records(orders)
df = df.groupby(['order__id'])['product__name'].apply(list).to_list()

优化建议

1. 利用Django ORM预查询减少数据库交互

从Order模型出发,通过prefetch_related和select_related一次性拉取所有关联数据,避免N+1查询问题:

from django.db.models import Prefetch

# 预加载关联的OrderedProduct及对应的Product
orders = Order.objects.prefetch_related(
    Prefetch(
        'orderedproduct_set',
        queryset=OrderedProduct.objects.select_related('product'),
        to_attr='ordered_products'
    )
).all()

# 构造DataFrame数据
data = [
    {'order': order.id, 'products': [op.product.name for op in order.ordered_products]}
    for order in orders
]

df = pd.DataFrame(data)

这种方式大幅减少数据库查询次数,在数据量较大时能明显提升性能。

2. 数据库层面聚合(PostgreSQL专属)

如果使用PostgreSQL数据库,可直接用ArrayAgg聚合函数在数据库端生成商品列表,把聚合压力转移到数据库:

from django.contrib.postgres.aggregates import ArrayAgg

# 直接聚合每个订单的商品名列表
order_product_data = OrderedProduct.objects.values('order__id').annotate(
    products=ArrayAgg('product__name')
).order_by('order__id')

# 转换为目标DataFrame
df = pd.DataFrame.from_records(order_product_data).rename(columns={'order__id': 'order'})

此方法无需在Python端做分组处理,效率最高。

3. 优化现有Pandas分组逻辑

若坚持原有查询方式,可优化Pandas的分组操作,避免apply(list)的额外开销:

orders = OrderedProduct.objects.all().values('order__id', 'product__name')
df = pd.DataFrame.from_records(orders)
# 用agg(list)替代apply(list),直接生成带索引的DataFrame后重置索引并重命名列
df = df.groupby('order__id')['product__name'].agg(list).reset_index(name='products')
df.rename(columns={'order__id': 'order'}, inplace=True)

相比原代码,此方式直接生成目标结构的DataFrame,无需额外转换步骤。

内容的提问来源于stack exchange,提问作者Avishka Dambawinna

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 18:57:17