Django中无需for循环获取指定客户订购产品列表的方法
问题说明
我是Django和SQL的初学者,目前正尝试通过解决简单问题入门相关技术。我定义了Client(客户)、Product(产品)、Order(订单)3个模型,想要实现列出指定客户所订购全部产品的需求,模型定义如下:
class Client(models.Model): name = models.CharField(max_length=32) ..... class Product(models.Model): product_name = models.CharField(max_length=32) ..... class Order(models.Model): client = models.ForeignKey(Client,on_delete=models.CASCADE) product = models.ForeignKey(Product,on_delete=models.CASCADE) .....
我当前的实现代码如下:
client= Client.objects.get(id=1) # 目标客户 orders = client.order_set.all() # 另一种等价写法 orders = Order.objects.filter(client=client) list_of_orders=[order.product for order in orders]
想确认是否存在更优的Django原生特性实现方案,不需要手写for循环就能获取目标产品列表。
实现方案
完全可以用Django ORM原生的跨关联查询实现,不需要手写循环,性能比当前写法更好,还能避免常见的N+1查询问题。
最简洁的写法是直接查询Product表,通过关联路径过滤出对应客户的订单关联的产品:
client = Client.objects.get(id=1) # 自动完成表关联,直接返回该客户购买过的所有产品的QuerySet product_list = Product.objects.filter(order__client=client)
如果同一个客户有多条订单购买了同一个产品,不想返回重复的产品记录,只需要在后面加.distinct()去重即可:
product_list = Product.objects.filter(order__client=client).distinct()
方案优势
- 完全使用Django原生ORM API,不需要手写for循环或者列表推导
- 底层只会生成1条联表查询的SQL,不会出现原写法中「先查所有订单,再逐条查询每个订单对应产品」的N+1性能问题,数据量越大性能优势越明显
- 返回的是标准的
QuerySet对象,后续可以直接链式调用排序、筛选、分页等ORM方法,灵活性更高
如果你不需要完整的Product模型实例,只需要产品的部分字段,还可以用values()或values_list()直接提取指定字段,进一步减少性能开销:
# 直接返回包含产品id、名称的字典列表,不需要实例化Product模型 product_simple_list = client.order_set.values('product__id', 'product__product_name').distinct()
内容的提问来源于stack exchange,提问作者Fabrizio
相关产品推荐
相关产品推荐

