Django - 根据需要调用模型的方法来过滤和从反向外键中预取数据

时间:2015-03-20 14:37:10

标签: django django-models django-queryset django-filters

我目前正在尝试提高服务器的性能,而且我已经用了几天工作,到目前为止我还没有找到解决方案。 我使用django 1.5并且没有机会升级到更新的版本。

鉴于这些模型:

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

class Store(models.Model):
    name = models.CharField()
    closed = models.BooleanField()
    store = models.ForeignKey(Company)

根据文档,如果我想预取反转的外键,我可以这样做:

companies = Company.objects.filter(
    name__startswith = "stackoverflow",
    ).prefetch_related("store_set")

for company in companies:
    open_stores = company.store_set.all() 

这很好用,一切都在1个查询中完成。但是,我只想要开放的商店。这样做会导致额外的查询:

for company in companies:
    open_stores = company.store_set.filter(open = True)

所以,这根本没用。 我如何预取所有已打开的商店?

我的一个想法是做类似的事情:

class Company(models.Model):
    name = models.CharField()
    prefetched_stores = None
    def _prefetch_stores(self):
        return self.store_set.filter(closed = False)
    def __init__(self, *args, **kwargs):
        force_prefetch = kwargs.pop("force_prefetch" or None)
        if force_prefetch:
            self.prefetched_stores = self._prefetch_stores()

class Store(models.Model):
    name = models.CharField()
    closed = models.BooleanField()
    store = models.ForeignKey(Company)

这个问题的一个问题是我并不总是想要预先加载商店,所以init不是正确的地方(并且很可能会引起一堆副作用)但我希望你能理解。

这是可能的还是我走到了死胡同?如果可能的话,我该怎么做?

1 个答案:

答案 0 :(得分:1)

只需在python代码中过滤商店:

for company in companies:
    open_stores = [s for s in company.store_set.all() if not s.closed]

或手动预取商店:

companies = Company.objects.filter(name__startswith="stackoverflow")

open_stores_d = {}
for store in Store.objects.filter(closed=False, company__in=companies):
    open_stores_d.setdefault(store.company, []).append(store)

for company in companies:
    open_stores = open_stores_d.get(company, [])