缓存查询集并重新评估

时间:2009-08-28 06:37:12

标签: django django-queryset django-database

我将发布一些不完整的代码,以使示例变得简单。我正在运行递归函数来计算层次结构上的一些指标。

类别类别(models.Model):

parent = models.ForeignKey('self', null=True, blank=True, related_name='children', default=1)

def compute_metrics(self, shop_object, metric_queryset=None, rating_queryset=None)
    if(metric_queryset == None):
        metric_queryset = Metric.objects.all()
    if(rating_queryset == None):
        rating_queryset = Rating.objects.filter(shop_object=shop_object)

    for child in self.children.all():
        do stuff
        child_score = child.compute_metrics(shop_object, metric_queryset, rating_queryset)

    metrics_in_cat = metric_queryset.filter(category=self) 
    for metric in metrics_in_cat
          do stuff

我希望有足够的代码来查看正在发生的事情。我在这里的是一个递归函数,它只会运行一次这些查询,然后传递结果。这似乎现在似乎没有发生,而且它正在扼杀性能。这是PHP / MySQL(就像我在使用Django之后不喜​​欢它们一样!)我可以运行一次查询并将其传递下来。

根据我对Django的查询集的理解,它们不会在我的if queryset == None然后queryset = stuff部分进行评估。我怎么强迫这个?当我做metric_queryset.filter(category=self)之类的事情时会重新评估吗?

我不关心数据的新鲜度。我只想从数据库中读取一次指标和评级,然后在以后过滤它们而不再次访问数据库。这是一个令人沮丧的问题,感觉应该有一个非常简单的答案。酸洗看起来可以起作用,但在Django文档中没有很好地解释。

1 个答案:

答案 0 :(得分:3)

我认为这里的问题是你在递归调用之前没有评估查询集。如果您使用list()强制评估查询集,那么它应该只访问数据库一次。请注意,您必须将metrics_in_cat行更改为python级别过滤器,而不是使用查询集过滤器。

parent = models.ForeignKey('self', null=True, blank=True, related_name='children', default=1)

def compute_metrics(self, shop_object, metric_queryset=None, rating_queryset=None)
    if(metric_queryset is None):
        metric_queryset = list([Metric.objects.all())
    if(rating_queryset is None):
        rating_queryset = list(Rating.objects.filter(shop_object=shop_object))

    for child in self.children.all():
        # do stuff
        child_score = child.compute_metrics(shop_object, metric_queryset, rating_queryset)

    # metrics_in_cat = metric_queryset.filter(category=self)
    metrics_in_cat = [m for m in metric_queryset if m.category==self]
    for metric in metrics_in_cat
        # do stuff