直接在模板

时间:2016-07-18 19:53:55

标签: django prefetch

我在模板中显示以下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和我尝试过的东西不起作用)

1 个答案:

答案 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()赢得'是适当的还是误导性的。)