2009-08-28 97 views
1

我打算发布一些不完整的代码以使示例变得简单。我正在运行递归函数来计算层次结构上的一些度量标准。缓存查询集和重新评估

类类别(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)这样的事情时,它会被重新评估吗?

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

回答

3

我认为这里的问题是你直到递归调用之后才评估queryset。如果您使用list()强制对查询集进行评估,那么它只应该击中数据库一次。请注意,您必须将metrics_in_cat行更改为python级别筛选器,而不是使用queryset筛选器。

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