Django ORM关联查询问题:使用select_related获取关联数据失败
我想获取所有关联模型的数据,但目前只能拿到部分关联数据。为了避免N+1查询问题,我尝试使用select_related()和prefetch_related()方法,却遇到了报错。
模型定义
class OrderList(models.Model): order_id=models.CharField(max_length=100) order_status=models.CharField(max_length=100) class ProductInOrder(models.Model): order_key=models.ForeignKey(OrderList, on_delete=models.CASCADE, related_name="order_key") product_id=models.CharField(max_length=100) product_price=models.CharField(max_length=100) class MemosInProduct(models.Model): product_key=models.ForeignKey(ProductInOrder, on_delete=models.CASCADE, related_name="product_key") memo=models.CharField(max_length=100) # 其他代码...
模型关系:一个OrderList对应多个ProductInOrder(一对多),一个ProductInOrder对应多个MemosInProduct(一对多)。
尝试的操作及问题
我在Django Shell中执行了以下代码:
order_list=OrderList.objects.select_related("order_key", "product_key").all()
预期结果
希望能获取包含所有关联数据的OrderList集合,可通过以下方式访问深层关联数据:
order_list[0].order_key[0].product_key[0].memo
order_list[0].order_key[0].product_key[1].memo
order_list[0].order_key[1].product_key[0].memo
...
实际报错
Invalid field name(s) given in select_related: 'order_key', 'product_key'. Choices are: (none)
我还尝试了从MemosInProduct出发查询,但结果不符合预期:
order_list=MemosInProduct.objects.select_related("order_key", "product_key").all()
核心问题:混淆了select_related和prefetch_related的适用场景
select_related()仅适用于正向一对一、多对一关系,它通过SQL JOIN语句一次性拉取关联数据;而你用到的order_key是OrderList的反向一对多关联(由ProductInOrder的外键定义,related_name="order_key"是给OrderList添加的反向关联名),反向一对多、多对多关系必须用prefetch_related()处理——它先查询主表,再批量查询关联表,最后在Python层面完成数据关联。
正确的查询写法
要一次性获取OrderList及其关联的所有ProductInOrder和MemosInProduct,可以用两种写法:
- 嵌套
Prefetch的明确写法:
from django.db.models import Prefetch order_list = OrderList.objects.prefetch_related( Prefetch('order_key', queryset=ProductInOrder.objects.prefetch_related('product_key')) ).all()
- 简洁的链式关联写法:
order_list = OrderList.objects.prefetch_related('order_key__product_key').all()
查询完成后,就可以按预期访问关联数据了:
# 示例:访问第一个订单的第一个商品的第一个备注 print(order_list[0].order_key.all()[0].product_key.all()[0].memo)
注意:反向一对多的关联对象是QuerySet,需要用.all()获取所有关联项;在Django模板中遍历则无需额外添加.all()。
为什么之前的代码报错?
OrderList本身没有order_key或product_key这类正向关联字段,order_key是它的反向关联,select_related()无法识别,因此直接报错。- 若从
MemosInProduct出发查询,需使用正向关联的字段路径才能正确获取数据,但这是从备注向上追溯订单,和你“从订单向下获取所有关联数据”的需求不符:
memos = MemosInProduct.objects.select_related('product_key__order_key').all() # 可这样访问:memos[0].product_key.order_key.order_id
补充说明
- 正向关联:从外键所在模型指向被关联模型(比如
ProductInOrder通过order_key访问OrderList),属于多对一关系,用select_related。 - 反向关联:从被关联模型指向外键所在模型(比如
OrderList通过order_key访问所有ProductInOrder),属于一对多关系,用prefetch_related。
内容的提问来源于stack exchange,提问作者Loire

