我在模板中显示以下for循环的数据
{% for soproduct in list_soproduct %}
{% for bomversion in soproduct.product.material.default_active_bomversions %}
{% for bom in bomversion.bom_set.all %}
{% for production_order in bom.production_order_set.all %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
数据来自以下型号
class SOproduct(models.Model):
product = models.ForeignKey(Product, on_delete=models.PROTECT)
so = models.ForeignKey(SO, on_delete=models.PROTECT)
quantity = models.DecimalField(max_digits=13, decimal_places=3, default = 0)
class Product(models.Model):
version = IntegerVersionField( )
GTIN = models.CharField(max_length=30)
name = models.CharField(max_length=30)
description = models.TextField(null=True, blank=True)
creation_time = models.DateTimeField(auto_now_add=True, blank=True)
material = models.ForeignKey(Material, on_delete=models.PROTECT)
class BOMVersion(models.Model):
name = models.CharField(max_length=200,null=True, blank=True)
description = models.TextField(null=True, blank=True)
material = models.ForeignKey(Material)
is_active = models.BooleanField(default=False)
is_default = models.BooleanField(default=False)
class BOMVersion_default_active_Manager(models.Manager):
def get_queryset(self):
return super(BOMVersion_default_active, self).get_queryset().filter(is_default=True,is_active=True)
class BOMVersionQuerySet(models.QuerySet):
def active(self):
return self.filter(is_active=True)
def default(self):
return self.filter(is_default=True)
class BOM(models.Model):
bomversion = models.ForeignKey(BOMVersion)
material = models.ForeignKey(Material)
quantity = models.DecimalField(default =0 ,max_digits=19, decimal_places=3)
class Production_order(models.Model):
BOM = models.ForeignKey(BOM, on_delete=models.PROTECT)
soproduct = models.ForeignKey(SOproduct, on_delete=models.PROTECT)
quantity_order = models.DecimalField(max_digits=19, decimal_places=3)
在视图中我使用以下预取对象
soproduct = SOproduct.objects.select_related('product__material').prefetch_related(
Prefetch(
'product__material__bomversion_set',
queryset=BOMVersion.objects.default().active(),
to_attr='default_active_bomversions'
)
)
我的问题是最深的循环
用于bom.production_order_set.all中的production_order
我想通过soproduct进行过滤,所以我想知道如何修改现有的预取以满足此要求,如果可能的话?或者我唯一的选择是直接在模板>
中过滤(我真的不明白Prefetch和我尝试过的东西不起作用)
答案 0 :(得分:1)
老实说,我不确定这是否会奏效,但试一试:
soproduct = SOproduct.objects.select_related('product__material').prefetch_related(
Prefetch(
'product__material__bomversion_set',
queryset=BOMVersion.objects.default().active().prefetch_related(
Prefetch('bom_set', queryset=BOM.objects.all().prefetch_related('production_order_set'))
),
to_attr='default_active_bomversions'
)
)
然后在模板中,您可以进行简单的if-check。
{% for soproduct in list_soproduct %}
{% for bomversion in soproduct.product.material.default_active_bomversions %}
{% for bom in bomversion.bom_set.all %}
{% for production_order in bom.production_order_set.all %}
{% if production_order.soproduct == soproduct %}
do my staff
{% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
基本上prefetch_related
做的是不是通过SQL JOINs
获取相关数据(这是select_related
做的),而是通过单独查询然后合并python中的结果。我认为docs可以很好地解释这一点。
通过使用自定义Prefetch
对象,我们可以做两件事
1)更改django将使用的默认queryset
prefetch_related
(可用于过滤结果)和
2)更改django将存储预取数据的属性(默认情况下将其存入myobject.related_set.all()
这在我们执行其他过滤时会很有用,这些过滤会更改结果的上下文并related_set.all()
赢得'是适当的还是误导性的。)