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

Django - Call model's method on demand to filter and prefetch data from a reversed foreignkey

我目前正在尝试提高我的服务器的性能,我已经为此工作了几天,但到目前为止我还没有找到解决方案。 我使用的是 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 = "Whosebug",
    ).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 不是正确的地方(并且很可能会导致一堆附带问题)但我希望你明白了。

这有可能吗?还是我已经走到了死胡同?如果可能,我该怎么做?

只需筛选 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="Whosebug")

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, [])