Django中复杂多模型查询的优化

时间:2012-10-01 16:35:15

标签: python django django-models many-to-many django-orm

我需要轻松控制在哪个网站上显示的产品,并且由于有很多产品,我还想通过类别,制作人和标签设置产品网站。因此,如果产品OR(其类别及其生产者及其标签之一)链接到该网站,我会在网站上显示产品。我最终得到的代码如下(简化):

from django.db.models import Model, ManyToManyField, ForeignKey, BooleanField

class Site(Model):
    enabled = BooleanField()

class Producer(Model):
    sites = ManyToManyField(Site)

class Category(Model):
    sites = ManyToManyField(Site)

class Tag(Model):
    sites = ManyToManyField(Site)

class Product(Model):
    producer = ForeignKey(Producer)
    category = ForeignKey(Category)
    tags     = ManyToManyField(Tag)
    sites    = ManyToManyField(Site)

    def get_site_ids(self):
        if self.sites.exists():
            return list(self.sites.values_list('id', flat=True))
        else:
            p = list(self.producer.sites.values_list('id', flat=True))
            c = list(self.category.sites.values_list('id', flat=True))
            t = sum([list(tag.sites.values_list('id', flat=True)) for tag in self.tags.all()], [])
            ids = set.intersection(set(p), set(c), set(t))
            return ids

我的问题是如何优化get_sites方法?是否可以加入一些查询?


更新:我对网站ID感兴趣,网站ID将被搜索引擎索引和存储。

2 个答案:

答案 0 :(得分:1)

如果可能,您应该尝试在数据库级别执行您想要执行的所有操作。这样的事情应该让你开始。

from django.db.models import Sum
self.objects.select_related("producer__sites",
                            "category__sites",
                            "tags__sites",
                            "sites").annotate(tag_count=Sum("tags__sites__id"))

select_related返回Product模型,其中填充了生产者,类别,标签和网站参考。这还包括生产者,类别和标签中的sites引用。这使得Django对数据库的查询次数减少了。

annotate为名为Model的返回tag_count实例添加了一个属性,该实例中包含tags_ sites _id的总和。

Django QuerySet Reference可能是一个很好的帮助,因为我不知道你想要返回的确切性质。

答案 1 :(得分:1)

是的,您可以使用select_related和/或prefetch_related减少Django中的查询数量。

但是,select_related仅适用于外键和一对一关系。由于您的产品型号中包含ManyToMany,因此您应使用prefetch_related来减少Product.get_sites()中的查询。