不直接相关的Django预取表

bdo*_*leu 8 django

使用以下模型是否可以获取Category对象并预取OrderLine以便它可以被访问category.orderlines.all()

class Category(models.Model):
    name = models.CharField(...)

class Product(models.Model):
    category = models.ForeignKey(Category, related_name='products', ...)
    name = models.CharField(...)
    price = models.DecimalField(...)

class OrderLine(models.Model):
    product = models.ForeignKey(Product, related_name='orderlines', ...)
Run Code Online (Sandbox Code Playgroud)

我知道您可以通过产品进行嵌套预取,但我想OrderLine直接从 a访问对象Category而不是通过Product

from django.db.models import Prefetch

categories = Category.objects.prefetch_related(Prefetch(
    'products__orderlines',
    queryset=OrderLine.objects.filter(...)
))

for category in categories:
    for product in category.products.all():
        for line in product.orderlines.all():
            ...
Run Code Online (Sandbox Code Playgroud)

预期用途:

for category in categories:
    for line in category.orderlines.all():
        ...
Run Code Online (Sandbox Code Playgroud)

更新

添加to_attr='orderlines'结果:

ValueError: to_attr=orderlines 与 Product 模型上的字段冲突。

更改属性名称to_attr='lines'不会导致错误,但不会将属性添加到Category对象中。它预取Product然后lines为每个产品添加一个属性。

bdo*_*leu 2

我最接近的方法是使用ArraySubquery。唯一的缺点是它lines是字典列表而不是模型实例。

Category.objects.annotate(
    lines=ArraySubquery(
        OrderLine.objects
        .filter(category=OuterRef('id'))
        .values(json=JSONObject(
            id='id',
            product_name='product__name',
            quantity='quantity',
        ))
    )
)
Run Code Online (Sandbox Code Playgroud)